summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-22 18:42:18 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-22 18:42:18 +0000
commit22088debca3b88ed45a7767e915511712e968919 (patch)
tree3d5340b47d242dd4e874ebf668062eb4edfd247e
parent6fd84321d69ebe307eab32be326dc77573c0687d (diff)
downloadgitlab-ce-22088debca3b88ed45a7767e915511712e968919.tar.gz
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
-rw-r--r--doc/development/testing_guide/frontend_testing.md32
-rw-r--r--spec/frontend/helpers/fake_date.js49
-rw-r--r--spec/frontend/helpers/fake_date_spec.js33
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/C++.gitignore0
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/Java.gitignore0
5 files changed, 114 insertions, 0 deletions
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index ef9fd748dbb..d0dcbda4a6a 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -638,6 +638,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
diff --git a/spec/frontend/helpers/fake_date.js b/spec/frontend/helpers/fake_date.js
new file mode 100644
index 00000000000..8417b1c520a
--- /dev/null
+++ b/spec/frontend/helpers/fake_date.js
@@ -0,0 +1,49 @@
+// 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;
+};
diff --git a/spec/frontend/helpers/fake_date_spec.js b/spec/frontend/helpers/fake_date_spec.js
new file mode 100644
index 00000000000..8afc8225f9b
--- /dev/null
+++ b/spec/frontend/helpers/fake_date_spec.js
@@ -0,0 +1,33 @@
+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);
+ });
+ });
+});
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
index 259148fa18f..259148fa18f 100755..100644
--- a/vendor/gitignore/C++.gitignore
+++ b/vendor/gitignore/C++.gitignore
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
index a1c2a238a96..a1c2a238a96 100755..100644
--- a/vendor/gitignore/Java.gitignore
+++ b/vendor/gitignore/Java.gitignore