Commit b3917027 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@13-3-stable-ee

parent 4588bbc9
......@@ -691,6 +691,38 @@ unit tests.
Instead of `setImmediate`, use `jest.runAllTimers` or `jest.runOnlyPendingTimers` to run pending timers.
The latter is useful when you have `setInterval` in the code. **Remember:** our Jest configuration uses fake timers.
## Avoid non-deterministic specs
Non-determinism is the breeding ground for flaky and brittle specs. Such specs end up breaking the CI pipeline, interrupting the work flow of other contributors.
1. Make sure your test subject's collaborators (e.g., axios, apollo, lodash helpers) and test environment (e.g., Date) behave consistently across systems and over time.
1. Make sure tests are focused and not doing "extra work" (e.g., needlessly creating the test subject more than once in an individual test)
### Faking `Date` for determinism
Consider using `useFakeDate` to ensure a consistent value is returned with every `new Date()` or `Date.now()`.
```javascript
import { useFakeDate } from 'helpers/fake_date';
describe('cool/component', () => {
useFakeDate();
// ...
});
```
### Faking `Math.random` for determinism
Consider replacing `Math.random` with a fake when the test subject depends on it.
```javascript
beforeEach(() => {
// https://xkcd.com/221/
jest.spyOn(Math, 'random').mockReturnValue(0.4);
});
```
## Factories
TBU
......
// Frida Kahlo's birthday (6 = July)
export const DEFAULT_ARGS = [2020, 6, 6];
const RealDate = Date;
const isMocked = val => Boolean(val.mock);
export const createFakeDateClass = ctorDefault => {
const FakeDate = new Proxy(RealDate, {
construct: (target, argArray) => {
const ctorArgs = argArray.length ? argArray : ctorDefault;
return new RealDate(...ctorArgs);
},
apply: (target, thisArg, argArray) => {
const ctorArgs = argArray.length ? argArray : ctorDefault;
return RealDate(...ctorArgs);
},
// We want to overwrite the default 'now', but only if it's not already mocked
get: (target, prop) => {
if (prop === 'now' && !isMocked(target[prop])) {
return () => new RealDate(...ctorDefault).getTime();
}
return target[prop];
},
getPrototypeOf: target => {
return target.prototype;
},
// We need to be able to set props so that `jest.spyOn` will work.
set: (target, prop, value) => {
// eslint-disable-next-line no-param-reassign
target[prop] = value;
return true;
},
});
return FakeDate;
};
export const useFakeDate = (...args) => {
const FakeDate = createFakeDateClass(args.length ? args : DEFAULT_ARGS);
global.Date = FakeDate;
};
export const useRealDate = () => {
global.Date = RealDate;
};
import { createFakeDateClass, DEFAULT_ARGS, useRealDate } from './fake_date';
describe('spec/helpers/fake_date', () => {
describe('createFakeDateClass', () => {
let FakeDate;
beforeAll(() => {
useRealDate();
});
beforeEach(() => {
FakeDate = createFakeDateClass(DEFAULT_ARGS);
});
it('should use default args', () => {
expect(new FakeDate()).toEqual(new Date(...DEFAULT_ARGS));
expect(FakeDate()).toEqual(Date(...DEFAULT_ARGS));
});
it('should have deterministic now()', () => {
expect(FakeDate.now()).not.toBe(Date.now());
expect(FakeDate.now()).toBe(new Date(...DEFAULT_ARGS).getTime());
});
it('should be instanceof Date', () => {
expect(new FakeDate()).toBeInstanceOf(Date);
});
it('should be instanceof self', () => {
expect(new FakeDate()).toBeInstanceOf(FakeDate);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment