184 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| /* eslint-disable import/no-commonjs, max-classes-per-file */
 | |
| 
 | |
| const { TestEnvironment } = require('jest-environment-jsdom');
 | |
| const { ErrorWithStack } = require('jest-util');
 | |
| const {
 | |
|   setGlobalDateToFakeDate,
 | |
|   setGlobalDateToRealDate,
 | |
| } = require('./__helpers__/fake_date/fake_date');
 | |
| const { TEST_HOST } = require('./__helpers__/test_constants');
 | |
| const { createGon } = require('./__helpers__/gon_helper');
 | |
| const { setupConsoleWatcher } = require('./__helpers__/console_watcher');
 | |
| 
 | |
| class CustomEnvironment extends TestEnvironment {
 | |
|   constructor({ globalConfig, projectConfig }, context) {
 | |
|     // Setup testURL so that window.location is setup properly
 | |
|     super({ globalConfig, projectConfig: { ...projectConfig, testURL: TEST_HOST } }, context);
 | |
| 
 | |
|     // Fake the `Date` for `jsdom` which fixes things like document.cookie
 | |
|     // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39496#note_503084332
 | |
|     setGlobalDateToFakeDate();
 | |
| 
 | |
|     this.jestConsoleWatcher = setupConsoleWatcher(this, context.console, {
 | |
|       ignores: [
 | |
|         /The updateQuery callback for fetchMore is deprecated/,
 | |
|         // TODO: Remove this and replace with localized calls to `ignoreVueConsoleWarnings`
 | |
|         // https://gitlab.com/gitlab-org/gitlab/-/issues/396779#note_1788506238
 | |
|         /^\[Vue warn\]: Missing required prop/,
 | |
|         /^\[Vue warn\]: Invalid prop/,
 | |
|         // TODO: Implement robust vue-demi switching logic.
 | |
|         // https://gitlab.com/groups/gitlab-org/-/epics/15340
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_PRIVATE_UTIL\)/,
 | |
| 
 | |
|         // [`@vue/compat`][1] provides configurable Vue 2 compatible
 | |
|         // APIs/behaviors, via flags. Some of these are considered
 | |
|         // ["fully compatible"][2], i.e., should still work if the given flag
 | |
|         // is enabled.
 | |
|         //
 | |
|         // When application code makes use of these Vue 2 APIs/behaviours,
 | |
|         // `@vue/compat` logs a warning to the console. These do not need to
 | |
|         // fail tests, since things should still work.
 | |
|         //
 | |
|         // [1]: https://v3-migration.vuejs.org/migration-build.html
 | |
|         // [2]: https://v3-migration.vuejs.org/migration-build.html#fully-compatible
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_MOUNT\)/,
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_EXTEND\)/,
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_PROTOTYPE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_SET\)/,
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_DELETE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation GLOBAL_OBSERVABLE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation CONFIG_KEY_CODES\)/,
 | |
|         /^\[Vue warn\]: \(deprecation CONFIG_WHITESPACE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_SET\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_DELETE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_EVENT_EMITTER\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_EVENT_HOOKS\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_CHILDREN\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_LISTENERS\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_SCOPED_SLOTS\)/,
 | |
|         /^\[Vue warn\]: \(deprecation INSTANCE_ATTRS_CLASS_STYLE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation OPTIONS_DATA_FN\)/,
 | |
|         /^\[Vue warn\]: \(deprecation OPTIONS_DATA_MERGE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation OPTIONS_BEFORE_DESTROY\)/,
 | |
|         /^\[Vue warn\]: \(deprecation OPTIONS_DESTROYED\)/,
 | |
|         /^\[Vue warn\]: \(deprecation WATCH_ARRAY\)/,
 | |
|         /^\[Vue warn\]: \(deprecation V_ON_KEYCODE_MODIFIER\)/,
 | |
|         /^\[Vue warn\]: \(deprecation CUSTOM_DIR\)/,
 | |
|         /^\[Vue warn\]: \(deprecation ATTR_FALSE_VALUE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation ATTR_ENUMERATED_COERCION\)/,
 | |
|         /^\[Vue warn\]: \(deprecation TRANSITION_GROUP_ROOT\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPONENT_ASYNC\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPONENT_FUNCTIONAL\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPONENT_V_MODEL\)/,
 | |
|         /^\[Vue warn\]: \(deprecation RENDER_FUNCTION\)/,
 | |
|         /^\[Vue warn\]: \(deprecation FILTERS\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_IS_ON_ELEMENT\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_V_BIND_SYNC\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_V_BIND_PROP\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_V_BIND_OBJECT_ORDER\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_V_ON_NATIVE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_V_FOR_REF\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_NATIVE_TEMPLATE\)/,
 | |
|         /^\[Vue warn\]: \(deprecation COMPILER_FILTERS\)/,
 | |
|       ],
 | |
|       // TODO: Remove this and replace with localized calls to `useConsoleWatcherThrowsImmediately`
 | |
|       // https://gitlab.com/gitlab-org/gitlab/-/issues/396779#note_1788506238
 | |
|       shouldThrowImmediately: true,
 | |
|     });
 | |
| 
 | |
|     const { IS_EE } = projectConfig.testEnvironmentOptions;
 | |
| 
 | |
|     this.global.IS_EE = IS_EE;
 | |
| 
 | |
|     // Set up global `gon` object
 | |
|     this.global.gon = createGon(IS_EE);
 | |
| 
 | |
|     // Set up global `gl` object
 | |
|     this.global.gl = {};
 | |
| 
 | |
|     this.rejectedPromises = [];
 | |
| 
 | |
|     this.global.promiseRejectionHandler = (error) => {
 | |
|       this.rejectedPromises.push(error);
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|      * window.fetch() is required by the apollo-upload-client library otherwise
 | |
|      * a ReferenceError is generated: https://github.com/jaydenseric/apollo-upload-client/issues/100
 | |
|      */
 | |
|     this.global.fetch = () => {};
 | |
| 
 | |
|     // Expose the jsdom (created in super class) to the global so that we can call reconfigure({ url: '' }) to properly set `window.location`
 | |
|     this.global.jsdom = this.dom;
 | |
| 
 | |
|     //
 | |
|     // Monaco-related environment variables
 | |
|     //
 | |
|     Object.defineProperty(this.global, 'matchMedia', {
 | |
|       writable: true,
 | |
|       value: (query) => ({
 | |
|         matches: false,
 | |
|         media: query,
 | |
|         onchange: null,
 | |
|         addListener: () => null, // deprecated
 | |
|         removeListener: () => null, // deprecated
 | |
|         addEventListener: () => null,
 | |
|         removeEventListener: () => null,
 | |
|         dispatchEvent: () => null,
 | |
|       }),
 | |
|     });
 | |
| 
 | |
|     /**
 | |
|      * JSDom doesn't have an own observer implementation, so this a Noop Observer.
 | |
|      * If you are testing functionality, related to observers, have a look at __helpers__/mock_dom_observer.js
 | |
|      *
 | |
|      * JSDom actually implements a _proper_ MutationObserver, so no need to mock it!
 | |
|      */
 | |
|     class NoopObserver {
 | |
|       /* eslint-disable no-useless-constructor, no-unused-vars, no-empty-function, class-methods-use-this */
 | |
|       constructor(callback) {}
 | |
|       disconnect() {}
 | |
|       observe(element, initObject) {}
 | |
|       unobserve(element) {}
 | |
|       takeRecords() {
 | |
|         return [];
 | |
|       }
 | |
|       /* eslint-enable no-useless-constructor, no-unused-vars, no-empty-function, class-methods-use-this */
 | |
|     }
 | |
| 
 | |
|     ['IntersectionObserver', 'PerformanceObserver', 'ResizeObserver'].forEach((observer) => {
 | |
|       if (this.global[observer]) {
 | |
|         throw new Error(
 | |
|           `We overwrite an existing Observer in jsdom (${observer}), are you sure you want to do that?`,
 | |
|         );
 | |
|       }
 | |
|       this.global[observer] = NoopObserver;
 | |
|     });
 | |
| 
 | |
|     // This is used internally by Sentry
 | |
|     // https://github.com/getsentry/sentry-javascript/blob/8.26.0/packages/browser/src/tracing/browserTracingIntegration.ts#L221
 | |
|     this.global.PerformanceObserver.supportedEntryTypes = ['noop'];
 | |
|   }
 | |
| 
 | |
|   async teardown() {
 | |
|     // Reset `Date` so that Jest can report timing accurately *roll eyes*...
 | |
|     setGlobalDateToRealDate();
 | |
| 
 | |
|     this.jestConsoleWatcher.dispose();
 | |
| 
 | |
|     // eslint-disable-next-line no-restricted-syntax
 | |
|     await new Promise(setImmediate);
 | |
| 
 | |
|     if (this.rejectedPromises.length > 0) {
 | |
|       throw new ErrorWithStack(
 | |
|         `Unhandled Promise rejections: ${this.rejectedPromises.join(', ')}`,
 | |
|         this.teardown,
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     await super.teardown();
 | |
|   }
 | |
| }
 | |
| 
 | |
| module.exports = CustomEnvironment;
 |