123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /* global __dirname */
- /* eslint import/no-nodejs-modules:0 */
- import fs from 'fs';
- import path from 'path';
- import TestStubFixtures from '../../../fixtures/js-stubs/types';
- const FIXTURES_ROOT = path.join(__dirname, '../../../fixtures');
- type Options = {
- /**
- * Flatten all fixtures to together into a single object
- */
- flatten?: boolean;
- };
- /**
- * Loads a directory of fixtures. Supports js and json fixtures.
- */
- export function loadFixtures(dir: string, opts: Options = {}): TestStubFixtures {
- const from = path.join(FIXTURES_ROOT, dir);
- const files = fs.readdirSync(from);
- // @ts-expect-error, this is a partial definition
- const fixtures: TestStubFixtures = {};
- for (const file of files) {
- const filePath = path.join(from, file);
- if (/[jt]sx?$/.test(file)) {
- const module = require(filePath);
- if (module.default) {
- throw new Error('Javascript fixtures cannot use default export');
- }
- fixtures[file] = module;
- continue;
- }
- if (/json$/.test(file)) {
- fixtures[file] = JSON.parse(fs.readFileSync(filePath).toString());
- continue;
- }
- throw new Error(`Invalid fixture type found: ${file}`);
- }
- if (opts.flatten) {
- // @ts-expect-error, this is a partial definition
- const flattenedFixtures: TestStubFixtures = {};
- for (const moduleKey in fixtures) {
- for (const moduleExport in fixtures[moduleKey]) {
- // Check if our flattenedFixtures already contains a key with the same export.
- // If it does, we want to throw and make sure that we dont silently override the fixtures.
- if (flattenedFixtures?.[moduleKey]?.[moduleExport]) {
- throw new Error(
- `Flatten will override module ${flattenedFixtures[moduleKey]} with ${fixtures[moduleKey][moduleExport]}`
- );
- }
- flattenedFixtures[moduleExport] = fixtures[moduleKey][moduleExport];
- }
- }
- return flattenedFixtures;
- }
- return fixtures;
- }
- const extensions = ['.js', '.ts', '.tsx', '.json'];
- // This is a mapping of special cases where fixture name does not map 1:1 to file name.
- // Some fixture files also contain more than one fixture so additional mappings are needed.
- // If you have added new fixtures and you are seeing an error being throw, please add the fixture
- const SPECIAL_MAPPING = {
- AllAuthenticators: 'authenticators',
- OrgRoleList: 'roleList',
- BitbucketIntegrationConfig: 'integrationListDirectory',
- DiscoverSavedQuery: 'discover',
- Entries123Base: 'entries',
- Entries123Target: 'entries',
- Events: 'events',
- EventsStats: 'events',
- EventStacktraceMessage: 'eventStacktraceException',
- GitHubIntegration: 'githubIntegration',
- GitHubIntegrationConfig: 'integrationListDirectory',
- GitHubIntegrationProvider: 'githubIntegrationProvider',
- MetricsField: 'metrics',
- MetricsSessionUserCountByStatusByRelease: 'metrics',
- MetricsTotalCountByReleaseIn24h: 'metrics',
- MOCK_RESP_VERBOSE: 'ruleConditions',
- OrgOwnedApps: 'integrationListDirectory',
- OutcomesWithReason: 'outcomes',
- PluginListConfig: 'integrationListDirectory',
- ProviderList: 'integrationListDirectory',
- PublishedApps: 'integrationListDirectory',
- SentryAppComponentAsync: 'sentryAppComponent',
- SentryAppInstalls: 'integrationListDirectory',
- SessionsField: 'sessions',
- SessionStatusCountByProjectInPeriod: 'sessions',
- SessionStatusCountByReleaseInPeriod: 'sessions',
- SessionUserCountByStatus: 'sessions',
- SessionUserCountByStatusByRelease: 'sessions',
- TagValues: 'tagvalues',
- VercelProvider: 'vercelIntegration',
- };
- function tryRequire(dir: string, name: string): any {
- if (SPECIAL_MAPPING[name]) {
- return require(path.resolve(dir, SPECIAL_MAPPING[name]));
- }
- for (const ext of extensions) {
- try {
- return require(path.resolve(dir, lowercaseFirst(name) + ext));
- } catch {
- // ignore
- }
- }
- throw new Error('Failed to resolve file');
- }
- function lowercaseFirst(value: string): string {
- return value.charAt(0).toLowerCase() + value.slice(1);
- }
- export function makeLazyFixtures<UserProvidedFixtures extends Record<any, any>>(
- fixturesDirectoryPath: string,
- userProvidedFixtures: UserProvidedFixtures
- ): TestStubFixtures & UserProvidedFixtures {
- const lazyFixtures = new Proxy(
- {},
- {
- get(target, prop: string) {
- if (target[prop]) {
- return target[prop];
- }
- if (userProvidedFixtures[prop]) {
- return userProvidedFixtures[prop];
- }
- try {
- const maybeModule = tryRequire(fixturesDirectoryPath, prop);
- for (const exportKey in maybeModule) {
- target[exportKey] = maybeModule[exportKey];
- }
- } catch (error) {
- return () => {
- throw new Error(
- error +
- '\n\n' +
- `Failed to resolve ${prop} fixture.
- - Your fixture does not map directly to file on disk or fixture file could be exporting > 1 fixture.
- - To resolve this, add a mapping to SPECIAL_MAPPING in loadFixtures.ts or ensure fixture export name maps to the file on disk.
- - If you are seeing this only in CI and you have followed the step above, check the exact casing of the file as it is case sensitive.
- `
- );
- };
- }
- if (target[prop] === undefined) {
- return () => {
- throw new Error(
- `Failed to resolve ${prop} fixture.
- - Your fixture does not map directly to file on disk or fixture file could be exporting > 1 fixture.
- - To resolve this, add a mapping to SPECIAL_MAPPING in loadFixtures.ts or ensure fixture export name maps to the file on disk.
- - If you are seeing this only in CI and you have followed the step above, check the exact casing of the file as it is case sensitive.`
- );
- };
- }
- return target[prop];
- },
- }
- );
- return lazyFixtures as TestStubFixtures & UserProvidedFixtures;
- }
|