Merge pull request #9255 from backstage/rugvip/role-jest
cli: bump to jest 27
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
The logger returned from `getVoidLogger` is now uses a silenced console transport instead.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Bump the version range of `jest` from `^26.0.1` to `^27.5.1`. You can find the complete list of breaking changes [here](https://github.com/facebook/jest/releases/tag/v27.0.0).
|
||||
|
||||
We strongly recommend to have completed the [package role migration](https://backstage.io/docs/tutorials/package-role-migration) before upgrading to this version, as the package roles are used to automatically determine the testing environment for each package. If you instead want to set an explicit test environment for each package, you can do so for example in the `"jest"` section in `package.json`. The default test environment for all packages is now `node`, which is also the new Jest default.
|
||||
|
||||
Note that one of the breaking changes of Jest 27 is that the `jsdom` environment no longer includes `setImmediate` and `clearImmediate`, which means you might need to update some of your frontend packages. Another notable change is that `jest.useFakeTimers` now defaults to the `'modern'` implementation, which also mocks microtasks.
|
||||
@@ -170,6 +170,7 @@ memoized
|
||||
microservice
|
||||
microservices
|
||||
microsite
|
||||
microtasks
|
||||
middleware
|
||||
minikube
|
||||
Minikube
|
||||
|
||||
@@ -108,7 +108,6 @@
|
||||
"aws-sdk-mock": "^5.2.1",
|
||||
"better-sqlite3": "^7.5.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"jest": "^26.0.1",
|
||||
"mock-fs": "^5.1.0",
|
||||
"msw": "^0.35.0",
|
||||
"mysql2": "^2.2.5",
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PassThrough } from 'stream';
|
||||
import * as winston from 'winston';
|
||||
|
||||
/**
|
||||
@@ -24,6 +23,6 @@ import * as winston from 'winston';
|
||||
*/
|
||||
export function getVoidLogger(): winston.Logger {
|
||||
return winston.createLogger({
|
||||
transports: [new winston.transports.Stream({ stream: new PassThrough() })],
|
||||
transports: [new winston.transports.Console({ silent: true })],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ describe('AzureUrlReader', () => {
|
||||
{
|
||||
url: 'com/a/b/blob/master/path/to/c.yaml',
|
||||
config: createConfig(),
|
||||
error: 'Invalid URL: com/a/b/blob/master/path/to/c.yaml',
|
||||
error: 'Invalid URL',
|
||||
},
|
||||
{
|
||||
url: '',
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"@backstage/backend-test-utils": "^0.1.23-next.0",
|
||||
"@backstage/cli": "^0.16.1-next.0",
|
||||
"@types/cron": "^1.7.3",
|
||||
"jest": "^26.0.1",
|
||||
"wait-for-expect": "^3.0.2"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
|
||||
import { Duration } from 'luxon';
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
import { migrateBackendTasks } from '../database/migrateBackendTasks';
|
||||
import { PluginTaskSchedulerImpl } from './PluginTaskSchedulerImpl';
|
||||
import { ConflictError, NotFoundError } from '@backstage/errors';
|
||||
import { AbortSignal } from 'node-abort-controller';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
@@ -56,6 +56,7 @@ describe('PluginTaskManagerImpl', () => {
|
||||
const { manager } = await init(databaseId);
|
||||
|
||||
const fn = jest.fn();
|
||||
const promise = new Promise(resolve => fn.mockImplementation(resolve));
|
||||
await manager.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
@@ -63,9 +64,8 @@ describe('PluginTaskManagerImpl', () => {
|
||||
fn,
|
||||
});
|
||||
|
||||
await waitForExpect(() => {
|
||||
expect(fn).toBeCalled();
|
||||
});
|
||||
await promise;
|
||||
expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal));
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
@@ -76,6 +76,7 @@ describe('PluginTaskManagerImpl', () => {
|
||||
const { manager } = await init(databaseId);
|
||||
|
||||
const fn = jest.fn();
|
||||
const promise = new Promise(resolve => fn.mockImplementation(resolve));
|
||||
await manager.scheduleTask({
|
||||
id: 'task2',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
@@ -83,9 +84,8 @@ describe('PluginTaskManagerImpl', () => {
|
||||
fn,
|
||||
});
|
||||
|
||||
await waitForExpect(() => {
|
||||
expect(fn).toBeCalled();
|
||||
});
|
||||
await promise;
|
||||
expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal));
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
@@ -98,6 +98,7 @@ describe('PluginTaskManagerImpl', () => {
|
||||
const { manager } = await init(databaseId);
|
||||
|
||||
const fn = jest.fn();
|
||||
const promise = new Promise(resolve => fn.mockImplementation(resolve));
|
||||
await manager.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
@@ -109,9 +110,8 @@ describe('PluginTaskManagerImpl', () => {
|
||||
await manager.triggerTask('task1');
|
||||
jest.advanceTimersByTime(5000);
|
||||
|
||||
await waitForExpect(() => {
|
||||
expect(fn).toBeCalled();
|
||||
});
|
||||
await promise;
|
||||
expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal));
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
@@ -171,6 +171,7 @@ describe('PluginTaskManagerImpl', () => {
|
||||
const { manager } = await init(databaseId);
|
||||
|
||||
const fn = jest.fn();
|
||||
const promise = new Promise(resolve => fn.mockImplementation(resolve));
|
||||
await manager
|
||||
.createScheduledTaskRunner({
|
||||
timeout: Duration.fromMillis(5000),
|
||||
@@ -181,9 +182,8 @@ describe('PluginTaskManagerImpl', () => {
|
||||
fn,
|
||||
});
|
||||
|
||||
await waitForExpect(() => {
|
||||
expect(fn).toBeCalled();
|
||||
});
|
||||
await promise;
|
||||
expect(fn).toHaveBeenCalledWith(expect.any(AbortSignal));
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
|
||||
@@ -131,11 +131,11 @@ describe('TaskWorker', () => {
|
||||
cadence: '* * * * * *',
|
||||
timeoutAfterDuration: Duration.fromMillis(60000).toISO(),
|
||||
};
|
||||
|
||||
const worker = new TaskWorker('task1', fn, knex, logger);
|
||||
const checkFrequency = Duration.fromObject({ milliseconds: 100 });
|
||||
const worker = new TaskWorker('task1', fn, knex, logger, checkFrequency);
|
||||
worker.start(settings);
|
||||
|
||||
waitForExpect(() => {
|
||||
await waitForExpect(() => {
|
||||
expect(fn).toBeCalledTimes(3);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -24,7 +24,7 @@ import { TaskFunction, TaskSettingsV2, taskSettingsV2Schema } from './types';
|
||||
import { delegateAbortController, nowPlus, sleep } from './util';
|
||||
import { CronTime } from 'cron';
|
||||
|
||||
const WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });
|
||||
const DEFAULT_WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });
|
||||
|
||||
/**
|
||||
* Performs the actual work of a task.
|
||||
@@ -32,17 +32,13 @@ const WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });
|
||||
* @private
|
||||
*/
|
||||
export class TaskWorker {
|
||||
private readonly taskId: string;
|
||||
private readonly fn: TaskFunction;
|
||||
private readonly knex: Knex;
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(taskId: string, fn: TaskFunction, knex: Knex, logger: Logger) {
|
||||
this.taskId = taskId;
|
||||
this.fn = fn;
|
||||
this.knex = knex;
|
||||
this.logger = logger;
|
||||
}
|
||||
constructor(
|
||||
private readonly taskId: string,
|
||||
private readonly fn: TaskFunction,
|
||||
private readonly knex: Knex,
|
||||
private readonly logger: Logger,
|
||||
private readonly workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,
|
||||
) {}
|
||||
|
||||
async start(settings: TaskSettingsV2, options?: { signal?: AbortSignal }) {
|
||||
try {
|
||||
@@ -63,7 +59,7 @@ export class TaskWorker {
|
||||
break;
|
||||
}
|
||||
|
||||
await sleep(WORK_CHECK_FREQUENCY, options?.signal);
|
||||
await sleep(this.workCheckFrequency, options?.signal);
|
||||
}
|
||||
this.logger.info(`Task worker finished: ${this.taskId}`);
|
||||
} catch (e) {
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
"uuid": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.16.1-next.0",
|
||||
"jest": "^26.0.1"
|
||||
"@backstage/cli": "^0.16.1-next.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -36,6 +36,25 @@ const transformIgnorePattern = [
|
||||
'typescript',
|
||||
].join('|');
|
||||
|
||||
// Provides additional config that's based on the role of the target package
|
||||
function getRoleConfig(role) {
|
||||
switch (role) {
|
||||
case 'frontend':
|
||||
case 'web-library':
|
||||
case 'common-library':
|
||||
case 'frontend-plugin':
|
||||
case 'frontend-plugin-module':
|
||||
return { testEnvironment: 'jsdom' };
|
||||
case 'cli':
|
||||
case 'backend':
|
||||
case 'node-library':
|
||||
case 'backend-plugin':
|
||||
case 'backend-plugin-module':
|
||||
default:
|
||||
return { testEnvironment: 'node' };
|
||||
}
|
||||
}
|
||||
|
||||
async function getProjectConfig(targetPath, displayName) {
|
||||
const configJsPath = path.resolve(targetPath, 'jest.config.js');
|
||||
const configTsPath = path.resolve(targetPath, 'jest.config.ts');
|
||||
@@ -50,6 +69,7 @@ async function getProjectConfig(targetPath, displayName) {
|
||||
// All configs are merged together to create the final config, with longer paths taking precedence.
|
||||
// The merging of the configs is shallow, meaning e.g. all transforms are replaced if new ones are defined.
|
||||
const pkgJsonConfigs = [];
|
||||
let closestPkgJson = undefined;
|
||||
let currentPath = targetPath;
|
||||
|
||||
// Some sanity check to avoid infinite loop
|
||||
@@ -59,6 +79,9 @@ async function getProjectConfig(targetPath, displayName) {
|
||||
if (exists) {
|
||||
try {
|
||||
const data = fs.readJsonSync(packagePath);
|
||||
if (!closestPkgJson) {
|
||||
closestPkgJson = data;
|
||||
}
|
||||
if (data.jest) {
|
||||
pkgJsonConfigs.unshift(data.jest);
|
||||
}
|
||||
@@ -115,6 +138,8 @@ async function getProjectConfig(targetPath, displayName) {
|
||||
testMatch: ['**/*.test.{js,jsx,ts,tsx,mjs,cjs}'],
|
||||
|
||||
transformIgnorePatterns: [`/node_modules/(?:${transformIgnorePattern})/`],
|
||||
|
||||
...getRoleConfig(closestPkgJson?.backstage?.role),
|
||||
};
|
||||
|
||||
// Use src/setupTests.ts as the default location for configuring test env
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
"handlebars": "^4.7.3",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"inquirer": "^8.2.0",
|
||||
"jest": "^26.0.1",
|
||||
"jest": "^27.5.1",
|
||||
"jest-css-modules": "^2.1.0",
|
||||
"jest-transform-yaml": "^1.0.0",
|
||||
"json-schema": "^0.4.0",
|
||||
|
||||
+5
-5
@@ -220,7 +220,7 @@ describe('GoogleAnalytics', () => {
|
||||
});
|
||||
|
||||
// Wait for any/all promises involved to settle.
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise(resolve => setTimeout(resolve));
|
||||
|
||||
// A pageview should have been fired immediately.
|
||||
const [command, data] = ReactGA.testModeAPI.calls[1];
|
||||
@@ -251,7 +251,7 @@ describe('GoogleAnalytics', () => {
|
||||
});
|
||||
|
||||
// Wait for any/all promises involved to settle.
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise(resolve => setTimeout(resolve));
|
||||
|
||||
// A pageview should have been fired immediately.
|
||||
const [command, data] = ReactGA.testModeAPI.calls[1];
|
||||
@@ -290,7 +290,7 @@ describe('GoogleAnalytics', () => {
|
||||
});
|
||||
|
||||
// Wait for any/all promises involved to settle.
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise(resolve => setTimeout(resolve));
|
||||
|
||||
// User ID should have been set after the pageview.
|
||||
const [setCommand, setData] = ReactGA.testModeAPI.calls[2];
|
||||
@@ -318,7 +318,7 @@ describe('GoogleAnalytics', () => {
|
||||
});
|
||||
|
||||
// Wait for any/all promises involved to settle.
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise(resolve => setTimeout(resolve));
|
||||
|
||||
// A pageview should have been fired immediately.
|
||||
const [command, data] = ReactGA.testModeAPI.calls[1];
|
||||
@@ -369,7 +369,7 @@ describe('GoogleAnalytics', () => {
|
||||
});
|
||||
|
||||
// Wait for any/all promises involved to settle.
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise(resolve => setTimeout(resolve));
|
||||
|
||||
// User ID should have been set first.
|
||||
const [setCommand, setData] = ReactGA.testModeAPI.calls[1];
|
||||
|
||||
@@ -44,6 +44,8 @@ jest.mock('@google-cloud/firestore', () => ({
|
||||
Firestore: jest.fn().mockImplementation(() => firestoreMock),
|
||||
}));
|
||||
|
||||
jest.useFakeTimers('legacy');
|
||||
|
||||
describe('FirestoreKeyStore', () => {
|
||||
const key = {
|
||||
kid: '123',
|
||||
@@ -69,11 +71,6 @@ describe('FirestoreKeyStore', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('can create an instance without settings', async () => {
|
||||
|
||||
@@ -345,7 +345,7 @@ describe('PlaceholderProcessor', () => {
|
||||
},
|
||||
),
|
||||
).rejects.toThrow(
|
||||
'Placeholder $text could not form a URL out of ./a/b/catalog-info.yaml and ../c/catalog-info.yaml, TypeError: Invalid base URL: ./a/b/catalog-info.yaml',
|
||||
/^Placeholder \$text could not form a URL out of \.\/a\/b\/catalog-info\.yaml and \.\.\/c\/catalog-info\.yaml, TypeError \[ERR_INVALID_URL\]/,
|
||||
);
|
||||
|
||||
expect(read).not.toBeCalled();
|
||||
|
||||
@@ -61,8 +61,7 @@
|
||||
"@backstage/cli": "^0.16.1-next.0",
|
||||
"@types/aws4": "^1.5.1",
|
||||
"supertest": "^6.1.3",
|
||||
"aws-sdk-mock": "^5.2.1",
|
||||
"bdd-lazy-var": "^2.6.0"
|
||||
"aws-sdk-mock": "^5.2.1"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
+13
-10
@@ -16,7 +16,6 @@
|
||||
import AWS from 'aws-sdk';
|
||||
import AWSMock from 'aws-sdk-mock';
|
||||
import { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator';
|
||||
import { get, def } from 'bdd-lazy-var';
|
||||
|
||||
describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
let role: any = undefined;
|
||||
@@ -48,7 +47,7 @@ describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
def('subject', () => {
|
||||
function executeTranslation() {
|
||||
AWSMock.mock('STS', 'assumeRole', (_params: any, callback: Function) => {
|
||||
callback(null, assumeResponse);
|
||||
});
|
||||
@@ -71,7 +70,7 @@ describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
mockedCredentials = undefined;
|
||||
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
it('returns a signed url for AWS credentials', async () => {
|
||||
// These credentials are not real.
|
||||
@@ -81,8 +80,8 @@ describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
||||
);
|
||||
|
||||
const subject = await get('subject');
|
||||
expect(subject.serviceAccountToken).toBeDefined();
|
||||
const response = await executeTranslation();
|
||||
expect(response.serviceAccountToken).toBeDefined();
|
||||
});
|
||||
|
||||
describe('When the role is assumed', () => {
|
||||
@@ -96,15 +95,17 @@ describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
|
||||
describe('When the role is valid', () => {
|
||||
it('returns a signed url for AWS credentials', async () => {
|
||||
const subject = await get('subject');
|
||||
expect(subject.serviceAccountToken).toBeDefined();
|
||||
const response = await executeTranslation();
|
||||
expect(response.serviceAccountToken).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the role is invalid', () => {
|
||||
it('returns the original AWS credentials', async () => {
|
||||
assumeResponse = undefined;
|
||||
await expect(get('subject')).rejects.toThrow(/Unable to assume role:/);
|
||||
await expect(executeTranslation()).rejects.toThrow(
|
||||
/Unable to assume role:/,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -112,7 +113,9 @@ describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
describe('When no AWS creds are available', () => {
|
||||
it('throws unable to get AWS credentials', async () => {
|
||||
mockedCredentials = new Error();
|
||||
await expect(get('subject')).rejects.toThrow('No AWS credentials found.');
|
||||
await expect(executeTranslation()).rejects.toThrow(
|
||||
'No AWS credentials found.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,7 +126,7 @@ describe('AwsIamKubernetesAuthTranslator tests', () => {
|
||||
'AKIAIOSFODNN7EXAMPLE',
|
||||
undefinedSecret,
|
||||
);
|
||||
await expect(get('subject')).rejects.toThrow(
|
||||
await expect(executeTranslation()).rejects.toThrow(
|
||||
'Invalid AWS credentials found.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -25,6 +25,9 @@ import { ConfigReader } from '@backstage/config';
|
||||
import { TaskContext, TaskSecrets } from './types';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
|
||||
// The Stream module is lazy loaded, so make sure it's in the module cache before mocking fs
|
||||
void winston.transports.Stream;
|
||||
|
||||
const realFiles = Object.fromEntries(
|
||||
[
|
||||
resolvePackagePath(
|
||||
|
||||
@@ -187,7 +187,7 @@ describe('StorageTaskBroker', () => {
|
||||
.mockRejectedValue(new Error('nah m8'));
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
broker.vacuumTasks({ timeoutS: 2 }).catch(fail);
|
||||
broker.vacuumTasks({ timeoutS: 2 });
|
||||
}, 500);
|
||||
|
||||
for (;;) {
|
||||
|
||||
@@ -42,8 +42,5 @@
|
||||
"dist",
|
||||
"config.d.ts"
|
||||
],
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
"configSchema": "config.d.ts"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@ import { runPeriodically } from './runPeriodically';
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe('runPeriodically', () => {
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
const flushPromises = async () => {
|
||||
const promise = new Promise(resolve => process.nextTick(resolve));
|
||||
jest.runAllTicks();
|
||||
await promise;
|
||||
};
|
||||
const advanceTimersByTime = async (time: number) => {
|
||||
jest.advanceTimersByTime(time);
|
||||
// Advancing the time with jest doesn't run all promises, but only sync code
|
||||
|
||||
@@ -21,19 +21,22 @@ import { LocalStoredShortcuts } from './LocalStoredShortcuts';
|
||||
import { ShortcutApi } from './ShortcutApi';
|
||||
|
||||
describe('LocalStoredShortcuts', () => {
|
||||
// eslint-disable-next-line jest/no-done-callback
|
||||
it('should observe shortcuts', async done => {
|
||||
it('should observe shortcuts', async () => {
|
||||
const shortcutApi: ShortcutApi = new LocalStoredShortcuts(
|
||||
MockStorageApi.create(),
|
||||
);
|
||||
const shortcut: Shortcut = { id: 'id', title: 'title', url: '/url' };
|
||||
|
||||
await shortcutApi.add(shortcut);
|
||||
shortcutApi.shortcut$().subscribe(data => {
|
||||
expect(data).toEqual(
|
||||
expect.arrayContaining([{ ...shortcut, id: expect.anything() }]),
|
||||
);
|
||||
done();
|
||||
|
||||
await new Promise<void>(resolve => {
|
||||
const subscription = shortcutApi.shortcut$().subscribe(data => {
|
||||
expect(data).toEqual(
|
||||
expect.arrayContaining([{ ...shortcut, id: expect.anything() }]),
|
||||
);
|
||||
subscription.unsubscribe();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import { DatabaseManager, getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
|
||||
import { TaskScheduler } from '@backstage/backend-tasks';
|
||||
import waitForExpect from 'wait-for-expect';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
@@ -145,7 +144,7 @@ describe('FactRetrieverEngine', () => {
|
||||
}
|
||||
|
||||
it.each(databases.eachSupportedId())(
|
||||
'Should update fact retriever schemas on initialization',
|
||||
'Should update fact retriever schemas on initialization with %s',
|
||||
async databaseId => {
|
||||
const schemaAssertionCallback = jest.fn((def: FactSchemaDefinition) => {
|
||||
expect(def.id).toEqual('test_factretriever');
|
||||
@@ -170,7 +169,7 @@ describe('FactRetrieverEngine', () => {
|
||||
);
|
||||
|
||||
it.each(databases.eachSupportedId())(
|
||||
'Should insert facts when scheduled step is run',
|
||||
'Should insert facts when scheduled step is run with %s',
|
||||
async databaseId => {
|
||||
function insertCallback({
|
||||
facts,
|
||||
@@ -193,7 +192,14 @@ describe('FactRetrieverEngine', () => {
|
||||
});
|
||||
}
|
||||
|
||||
engine = await createEngine(databaseId, insertCallback, () => {});
|
||||
const handler = jest.fn();
|
||||
engine = await createEngine(
|
||||
databaseId,
|
||||
insertCallback,
|
||||
() => {},
|
||||
undefined,
|
||||
{ ...testFactRetriever, handler },
|
||||
);
|
||||
await engine.schedule();
|
||||
const job: FactRetrieverRegistration = engine.getJobRegistration(
|
||||
testFactRetriever.id,
|
||||
@@ -203,13 +209,15 @@ describe('FactRetrieverEngine', () => {
|
||||
await engine.triggerJob(job.factRetriever.id);
|
||||
jest.advanceTimersByTime(5000);
|
||||
|
||||
await waitForExpect(() => {
|
||||
expect(testFactRetriever.handler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
entityFilter: testFactRetriever.entityFilter,
|
||||
}),
|
||||
);
|
||||
});
|
||||
const handlerParam = await new Promise(resolve =>
|
||||
handler.mockImplementation(resolve),
|
||||
);
|
||||
|
||||
await expect(handlerParam).toEqual(
|
||||
expect.objectContaining({
|
||||
entityFilter: testFactRetriever.entityFilter,
|
||||
}),
|
||||
);
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
|
||||
@@ -116,10 +116,11 @@ const additionalFacts = [
|
||||
];
|
||||
|
||||
describe('Tech Insights database', () => {
|
||||
const databases = TestDatabases.create();
|
||||
let store: TechInsightsStore;
|
||||
let testDbClient: Knex<any, unknown[]>;
|
||||
beforeAll(async () => {
|
||||
testDbClient = await TestDatabases.create().init('SQLITE_3');
|
||||
testDbClient = await databases.init('SQLITE_3');
|
||||
|
||||
store = (
|
||||
await initializePersistenceContext(testDbClient, {
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('RadarComponent', () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const errorApi = { post: () => {} };
|
||||
const { getByTestId, queryByTestId } = render(
|
||||
const { getByTestId, findByTestId } = render(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
@@ -73,7 +73,7 @@ describe('RadarComponent', () => {
|
||||
});
|
||||
expect(getByTestId('progress')).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => queryByTestId('tech-radar-svg'));
|
||||
await findByTestId('tech-radar-svg');
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('RadarPage', () => {
|
||||
svgProps: { 'data-testid': 'tech-radar-svg' },
|
||||
};
|
||||
|
||||
const { getByTestId, queryByTestId } = render(
|
||||
const { getByTestId, findByTestId } = render(
|
||||
wrapInTestApp(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techRadarApiRef, mockClient]]}>
|
||||
@@ -74,7 +74,7 @@ describe('RadarPage', () => {
|
||||
});
|
||||
expect(getByTestId('progress')).toBeInTheDocument();
|
||||
|
||||
await waitFor(() => queryByTestId('tech-radar-svg'));
|
||||
await findByTestId('tech-radar-svg');
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@ describe('RadarPage', () => {
|
||||
};
|
||||
jest.spyOn(mockClient, 'load');
|
||||
|
||||
const { getByText, getByTestId } = await renderInTestApp(
|
||||
const { getByText, findByTestId } = await renderInTestApp(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techRadarApiRef, mockClient]]}>
|
||||
<RadarPage {...techRadarProps} />
|
||||
@@ -94,12 +94,10 @@ describe('RadarPage', () => {
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() => getByTestId('tech-radar-svg'));
|
||||
|
||||
await expect(findByTestId('tech-radar-svg')).resolves.toBeInTheDocument();
|
||||
expect(
|
||||
getByText('Pick the recommended technologies for your projects'),
|
||||
).toBeInTheDocument();
|
||||
expect(getByTestId('tech-radar-svg')).toBeInTheDocument();
|
||||
expect(mockClient.load).toBeCalledWith(undefined);
|
||||
});
|
||||
|
||||
@@ -112,7 +110,7 @@ describe('RadarPage', () => {
|
||||
};
|
||||
jest.spyOn(mockClient, 'load');
|
||||
|
||||
const { getByTestId } = await renderInTestApp(
|
||||
const { findByTestId } = await renderInTestApp(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techRadarApiRef, mockClient]]}>
|
||||
<RadarPage {...techRadarProps} />
|
||||
@@ -120,9 +118,7 @@ describe('RadarPage', () => {
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() => getByTestId('tech-radar-svg'));
|
||||
|
||||
expect(getByTestId('tech-radar-svg')).toBeInTheDocument();
|
||||
await expect(findByTestId('tech-radar-svg')).resolves.toBeInTheDocument();
|
||||
expect(mockClient.load).toBeCalledWith('myId');
|
||||
});
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ class GetBBoxPolyfill {
|
||||
|
||||
Object.defineProperty(window.Element.prototype, 'getBBox', {
|
||||
writable: false,
|
||||
configurable: true,
|
||||
value: () => ({ x, y, width, height }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ describe('TechDocsStorageClient', () => {
|
||||
const promise = storageApi.syncEntityDocs(mockEntity).then();
|
||||
|
||||
// flush the event loop
|
||||
await new Promise(setImmediate);
|
||||
await new Promise(r => setTimeout(r));
|
||||
|
||||
const instance = MockedEventSource.mock
|
||||
.instances[0] as jest.Mocked<EventSource>;
|
||||
@@ -248,7 +248,7 @@ describe('TechDocsStorageClient', () => {
|
||||
const promise = storageApi.syncEntityDocs(mockEntity).then();
|
||||
|
||||
// flush the event loop
|
||||
await new Promise(setImmediate);
|
||||
await new Promise(r => setTimeout(r));
|
||||
|
||||
const instance = MockedEventSource.mock
|
||||
.instances[0] as jest.Mocked<EventSource>;
|
||||
|
||||
Reference in New Issue
Block a user