Skip to content

Commit

Permalink
Merge branch 'main' into improve-detect
Browse files Browse the repository at this point in the history
  • Loading branch information
SimenB authored Sep 19, 2023
2 parents 7e3584d + 1a96a5c commit c518fae
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 105 deletions.
9 changes: 7 additions & 2 deletions examples/snapshot/__tests__/clock.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import Clock from '../Clock';
jest.useFakeTimers().setSystemTime(1482363367071);

it('renders correctly', () => {
const tree = renderer.create(<Clock />).toJSON();
expect(tree).toMatchSnapshot();
const testRenderer = renderer.create(<Clock />);

try {
expect(testRenderer.toJSON()).toMatchSnapshot();
} finally {
testRenderer.unmount();
}
});
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"@types/babel__template": "^7.0.2",
"@types/node": "^16.10.0",
"@types/which": "^3.0.0",
"@types/ws": "8.5.1",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"ansi-regex": "^5.0.1",
Expand Down
180 changes: 89 additions & 91 deletions packages/jest-mock/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,101 +651,99 @@ export class ModuleMocker {
const prototypeSlots = this._getSlots(prototype);
// eslint-disable-next-line @typescript-eslint/no-this-alias
const mocker = this;
const mockConstructor = matchArity(
function (this: ReturnType<T>, ...args: Parameters<T>) {
const mockState = mocker._ensureMockState(f);
const mockConfig = mocker._ensureMockConfig(f);
mockState.instances.push(this);
mockState.contexts.push(this);
mockState.calls.push(args);
// Create and record an "incomplete" mock result immediately upon
// calling rather than waiting for the mock to return. This avoids
// issues caused by recursion where results can be recorded in the
// wrong order.
const mockResult: MockFunctionResult = {
type: 'incomplete',
value: undefined,
};
mockState.results.push(mockResult);
mockState.invocationCallOrder.push(mocker._invocationCallCounter++);

// Will be set to the return value of the mock if an error is not thrown
let finalReturnValue;
// Will be set to the error that is thrown by the mock (if it throws)
let thrownError;
// Will be set to true if the mock throws an error. The presence of a
// value in `thrownError` is not a 100% reliable indicator because a
// function could throw a value of undefined.
let callDidThrowError = false;

try {
// The bulk of the implementation is wrapped in an immediately
// executed arrow function so the return value of the mock function
// can be easily captured and recorded, despite the many separate
// return points within the logic.
finalReturnValue = (() => {
if (this instanceof f) {
// This is probably being called as a constructor
for (const slot of prototypeSlots) {
// Copy prototype methods to the instance to make
// it easier to interact with mock instance call and
// return values
if (prototype[slot].type === 'function') {
// @ts-expect-error no index signature
const protoImpl = this[slot];
// @ts-expect-error no index signature
this[slot] = mocker.generateFromMetadata(prototype[slot]);
// @ts-expect-error no index signature
this[slot]._protoImpl = protoImpl;
}
const mockConstructor = matchArity(function (
this: ReturnType<T>,
...args: Parameters<T>
) {
const mockState = mocker._ensureMockState(f);
const mockConfig = mocker._ensureMockConfig(f);
mockState.instances.push(this);
mockState.contexts.push(this);
mockState.calls.push(args);
// Create and record an "incomplete" mock result immediately upon
// calling rather than waiting for the mock to return. This avoids
// issues caused by recursion where results can be recorded in the
// wrong order.
const mockResult: MockFunctionResult = {
type: 'incomplete',
value: undefined,
};
mockState.results.push(mockResult);
mockState.invocationCallOrder.push(mocker._invocationCallCounter++);

// Will be set to the return value of the mock if an error is not thrown
let finalReturnValue;
// Will be set to the error that is thrown by the mock (if it throws)
let thrownError;
// Will be set to true if the mock throws an error. The presence of a
// value in `thrownError` is not a 100% reliable indicator because a
// function could throw a value of undefined.
let callDidThrowError = false;

try {
// The bulk of the implementation is wrapped in an immediately
// executed arrow function so the return value of the mock function
// can be easily captured and recorded, despite the many separate
// return points within the logic.
finalReturnValue = (() => {
if (this instanceof f) {
// This is probably being called as a constructor
for (const slot of prototypeSlots) {
// Copy prototype methods to the instance to make
// it easier to interact with mock instance call and
// return values
if (prototype[slot].type === 'function') {
// @ts-expect-error no index signature
const protoImpl = this[slot];
// @ts-expect-error no index signature
this[slot] = mocker.generateFromMetadata(prototype[slot]);
// @ts-expect-error no index signature
this[slot]._protoImpl = protoImpl;
}

// Run the mock constructor implementation
const mockImpl =
mockConfig.specificMockImpls.length > 0
? mockConfig.specificMockImpls.shift()
: mockConfig.mockImpl;
return mockImpl && mockImpl.apply(this, arguments);
}

// If mockImplementationOnce()/mockImplementation() is last set,
// implementation use the mock
let specificMockImpl = mockConfig.specificMockImpls.shift();
if (specificMockImpl === undefined) {
specificMockImpl = mockConfig.mockImpl;
}
if (specificMockImpl) {
return specificMockImpl.apply(this, arguments);
}
// Otherwise use prototype implementation
if (f._protoImpl) {
return f._protoImpl.apply(this, arguments);
}

return undefined;
})();
} catch (error) {
// Store the thrown error so we can record it, then re-throw it.
thrownError = error;
callDidThrowError = true;
throw error;
} finally {
// Record the result of the function.
// NOTE: Intentionally NOT pushing/indexing into the array of mock
// results here to avoid corrupting results data if mockClear()
// is called during the execution of the mock.
// @ts-expect-error reassigning 'incomplete'
mockResult.type = callDidThrowError ? 'throw' : 'return';
mockResult.value = callDidThrowError
? thrownError
: finalReturnValue;
}
// Run the mock constructor implementation
const mockImpl =
mockConfig.specificMockImpls.length > 0
? mockConfig.specificMockImpls.shift()
: mockConfig.mockImpl;
return mockImpl && mockImpl.apply(this, arguments);
}

// If mockImplementationOnce()/mockImplementation() is last set,
// implementation use the mock
let specificMockImpl = mockConfig.specificMockImpls.shift();
if (specificMockImpl === undefined) {
specificMockImpl = mockConfig.mockImpl;
}
if (specificMockImpl) {
return specificMockImpl.apply(this, arguments);
}
// Otherwise use prototype implementation
if (f._protoImpl) {
return f._protoImpl.apply(this, arguments);
}

return undefined;
})();
} catch (error) {
// Store the thrown error so we can record it, then re-throw it.
thrownError = error;
callDidThrowError = true;
throw error;
} finally {
// Record the result of the function.
// NOTE: Intentionally NOT pushing/indexing into the array of mock
// results here to avoid corrupting results data if mockClear()
// is called during the execution of the mock.
// @ts-expect-error reassigning 'incomplete'
mockResult.type = callDidThrowError ? 'throw' : 'return';
mockResult.value = callDidThrowError ? thrownError : finalReturnValue;
}

return finalReturnValue;
},
// eslint-disable-next-line unicorn/explicit-length-check
metadata.length || 0,
);
return finalReturnValue;
},
metadata.length || 0);

const f = this._createMockFunction(metadata, mockConstructor) as Mock;
f._isMockFunction = true;
Expand Down
1 change: 0 additions & 1 deletion packages/jest-snapshot/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ export default class SnapshotState {
}

getUncheckedCount(): number {
// eslint-disable-next-line unicorn/explicit-length-check
return this._uncheckedKeys.size || 0;
}

Expand Down
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2940,7 +2940,6 @@ __metadata:
"@types/babel__template": ^7.0.2
"@types/node": ^16.10.0
"@types/which": ^3.0.0
"@types/ws": 8.5.1
"@typescript-eslint/eslint-plugin": ^6.6.0
"@typescript-eslint/parser": ^6.6.0
ansi-regex: ^5.0.1
Expand Down Expand Up @@ -5413,15 +5412,6 @@ __metadata:
languageName: node
linkType: hard

"@types/ws@npm:8.5.1":
version: 8.5.1
resolution: "@types/ws@npm:8.5.1"
dependencies:
"@types/node": "*"
checksum: 4f06ff8b9e61201b28e7f4bbd0b30c5eeb32ed4d2c091554efc3b3b63ab56b4630c316a394be6bd6cc36bab87d0e5225ba55d0f7b170767175c26f7c14086bf9
languageName: node
linkType: hard

"@types/ws@npm:^8.5.5":
version: 8.5.5
resolution: "@types/ws@npm:8.5.5"
Expand Down

0 comments on commit c518fae

Please sign in to comment.