Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ describe('Jasmine to Vitest Transformer - Integration Tests', () => {
});

it('should handle spy call order', () => {
const spyA = vi.fn();
const spyB = vi.fn();
const spyA = vi.fn().mockName('spyA');
const spyB = vi.fn().mockName('spyB');
spyA();
spyB();
expect(Math.min(...vi.mocked(spyA).mock.invocationCallOrder)).toBeLessThan(Math.min(...vi.mocked(spyB).mock.invocationCallOrder));
Expand Down Expand Up @@ -387,7 +387,7 @@ describe('Jasmine to Vitest Transformer - Integration Tests', () => {
});

it('should handle spies throwing errors', () => {
const spy = vi.fn().mockImplementation(() => { throw new Error('Test Error') });
const spy = vi.fn().mockName('mySpy').mockImplementation(() => { throw new Error('Test Error') });
expect(() => spy()).toThrowError('Test Error');
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@ import {
transformExpectAsync,
transformExpectNothing,
transformSyntacticSugarMatchers,
transformToBeNullish,
transformToHaveBeenCalledBefore,
transformToHaveClass,
transformWithContext,
transformtoHaveBeenCalledBefore,
} from './transformers/jasmine-matcher';
import {
transformDefaultTimeoutInterval,
transformFail,
transformGlobalFunctions,
transformJasmineMembers,
transformTimerMocks,
transformUnknownJasmineProperties,
transformUnsupportedGlobalFunctions,
transformUnsupportedJasmineCalls,
} from './transformers/jasmine-misc';
import {
transformCreateSpy,
transformCreateSpyObj,
transformSpies,
transformSpyCallInspection,
Expand Down Expand Up @@ -116,16 +118,18 @@ const callExpressionTransformers = [
transformSyntacticSugarMatchers,
transformComplexMatchers,
transformSpies,
transformCreateSpy,
transformCreateSpyObj,
transformSpyReset,
transformSpyCallInspection,
transformtoHaveBeenCalledBefore,
transformToHaveBeenCalledBefore,
transformToHaveClass,
transformToBeNullish,

// **Stage 3: Global Functions & Cleanup**
// These handle global Jasmine functions and catch-alls for unsupported APIs.
transformTimerMocks,
transformGlobalFunctions,
transformUnsupportedGlobalFunctions,
transformUnsupportedJasmineCalls,
];

Expand All @@ -149,7 +153,7 @@ const expressionStatementTransformers = [
transformArrayWithExactContents,
transformExpectNothing,
transformFail,
transformDefaultTimeoutInterval,
transformJasmineMembers,
];

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('Jasmine to Vitest Transformer - Nested Transformations', () => {
await expectAsync(service.myProp).toBeResolvedTo(42);
`,
expected: `
vi.spyOn(service, 'myProp', 'get').mockReturnValue(Promise.resolve(42));
vi.spyOn(service, 'myProp', 'get').mockResolvedValue(42);
await expect(service.myProp).resolves.toEqual(42);
`,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export function transformAsymmetricMatchers(
return node;
}

export function transformtoHaveBeenCalledBefore(
export function transformToHaveBeenCalledBefore(
node: ts.Node,
{ sourceFile, reporter }: RefactorContext,
): ts.Node {
Expand Down Expand Up @@ -205,7 +205,7 @@ export function transformToHaveClass(
expectExpression = expectExpression.expression;
}

if (matcherName !== 'toHaveClass') {
if (matcherName !== 'toHaveClass' || !ts.isCallExpression(expectExpression)) {
return node;
}

Expand All @@ -218,21 +218,17 @@ export function transformToHaveClass(
const [className] = node.arguments;
const newExpectArgs: ts.Expression[] = [];

if (ts.isCallExpression(expectExpression)) {
const [element] = expectExpression.arguments;
const classListContains = ts.factory.createCallExpression(
createPropertyAccess(createPropertyAccess(element, 'classList'), 'contains'),
undefined,
[className],
);
newExpectArgs.push(classListContains);
const [element] = expectExpression.arguments;
const classListContains = ts.factory.createCallExpression(
createPropertyAccess(createPropertyAccess(element, 'classList'), 'contains'),
undefined,
[className],
);
newExpectArgs.push(classListContains);

// Pass the context message from withContext to the new expect call
if (expectExpression.arguments.length > 1) {
newExpectArgs.push(expectExpression.arguments[1]);
}
} else {
return node;
// Pass the context message from withContext to the new expect call
if (expectExpression.arguments.length > 1) {
newExpectArgs.push(expectExpression.arguments[1]);
}

const newExpect = createExpectCallExpression(newExpectArgs);
Expand Down Expand Up @@ -626,3 +622,63 @@ export function transformExpectNothing(

return replacement;
}

export function transformToBeNullish(
node: ts.Node,
{ sourceFile, reporter }: RefactorContext,
): ts.Node {
if (
!ts.isCallExpression(node) ||
!ts.isPropertyAccessExpression(node.expression) ||
node.arguments.length !== 0
) {
return node;
}

const pae = node.expression;
const matcherName = pae.name.text;
let isNegated = false;

let expectExpression = pae.expression;
if (ts.isPropertyAccessExpression(expectExpression) && expectExpression.name.text === 'not') {
isNegated = true;
expectExpression = expectExpression.expression;
}

if (matcherName !== 'toBeNullish' || !ts.isCallExpression(expectExpression)) {
return node;
}

reporter.reportTransformation(
sourceFile,
node,
'Transformed `.toBeNullish()` to a `element === null || element === undefined` check.',
);

const element = expectExpression.arguments[0];

const nullCheck = ts.factory.createBinaryExpression(
element,
ts.SyntaxKind.EqualsEqualsEqualsToken,
ts.factory.createNull(),
);

const undefinedCheck = ts.factory.createBinaryExpression(
element,
ts.SyntaxKind.EqualsEqualsEqualsToken,
ts.factory.createIdentifier('undefined'),
);

const fullExpression = ts.factory.createBinaryExpression(
nullCheck,
ts.SyntaxKind.BarBarToken,
undefinedCheck,
);

const newExpect = createExpectCallExpression([fullExpression]);
const newMatcher = isNegated ? ts.factory.createFalse() : ts.factory.createTrue();

return ts.factory.createCallExpression(createPropertyAccess(newExpect, 'toBe'), undefined, [
newMatcher,
]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,24 @@ describe('transformToHaveClass', () => {
});
});
});

describe('transformToBeNullish', () => {
const testCases = [
{
description: 'should transform toBeNullish',
input: `expect(element).toBeNullish();`,
expected: `expect(element === null || element === undefined).toBe(true);`,
},
{
description: 'should transform not.toBeNullish',
input: `expect(element).not.toBeNullish();`,
expected: `expect(element === null || element === undefined).toBe(false);`,
},
];

testCases.forEach(({ description, input, expected }) => {
it(description, async () => {
await expectTransformation(input, expected);
});
});
});
Loading
Loading