Skip to content

Commit

Permalink
Merge 86f1273 into 5557e93
Browse files Browse the repository at this point in the history
  • Loading branch information
connectdotz committed Nov 4, 2023
2 parents 5557e93 + 86f1273 commit abfe69f
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 41 deletions.
38 changes: 26 additions & 12 deletions src/test-provider/jest-test-run.ts
Expand Up @@ -7,7 +7,7 @@ export type TestRunProtocol = Pick<
'name' | 'enqueued' | 'started' | 'errored' | 'failed' | 'passed' | 'skipped' | 'end'
>;

export type CreateRun = (name: string) => vscode.TestRun;
export type CreateTestRun = (request: vscode.TestRunRequest, name: string) => vscode.TestRun;
export type EndProcessOption = { pid: string; delay?: number; reason?: string };
export type EndOption = EndProcessOption | { reason: string };
const isEndProcessOption = (arg?: EndOption): arg is EndProcessOption =>
Expand All @@ -27,11 +27,13 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {
private verbose: boolean;
private runCount = 0;
public readonly name: string;
private ignoreSkipped = false;

constructor(
name: string,
private context: JestTestProviderContext,
private createRun: CreateRun
private request: vscode.TestRunRequest,
private createRun: CreateTestRun
) {
this.name = `${this.context.ext.workspace.name}:${name}:${SEQ++}`;
this.output = context.output;
Expand All @@ -54,13 +56,19 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {
}
}
/**
* returns the underlying vscode.TestRun, if existing.
* If no run then create one with this.createRun and return it.
* returns the underlying vscode.TestRun, if no run then create one.
**/
private safeRun(): vscode.TestRun {
private vscodeRun(): vscode.TestRun {
if (!this._run) {
const runName = `${this.name} (${this.runCount++})`;
this._run = this.createRun(runName);

this._run = this.createRun(this.request, runName);
this._run.appendOutput(`\r\nTestRun "${runName}" started\r\n`);

// ignore skipped tests if there are more than one test to run
// this is to prevent the later runs override the previous runs's result
this.ignoreSkipped = this.request.include && this.request.include.length > 1 ? true : false;

if (this.verbose) {
console.log(`[${this.context.ext.workspace.name}] JestTestRun "${runName}": created.`);
}
Expand All @@ -70,32 +78,34 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {

// TestRunProtocol
public enqueued = (test: vscode.TestItem): void => {
this.safeRun().enqueued(test);
this.vscodeRun().enqueued(test);
};
public started = (test: vscode.TestItem): void => {
this.safeRun().started(test);
this.vscodeRun().started(test);
};
public errored = (
test: vscode.TestItem,
message: vscode.TestMessage | readonly vscode.TestMessage[],
duration?: number | undefined
): void => {
const _msg = this.context.ext.settings.runMode.config.showInlineError ? message : [];
this.safeRun().errored(test, _msg, duration);
this.vscodeRun().errored(test, _msg, duration);
};
public failed = (
test: vscode.TestItem,
message: vscode.TestMessage | readonly vscode.TestMessage[],
duration?: number | undefined
): void => {
const _msg = this.context.ext.settings.runMode.config.showInlineError ? message : [];
this.safeRun().failed(test, _msg, duration);
this.vscodeRun().failed(test, _msg, duration);
};
public passed = (test: vscode.TestItem, duration?: number | undefined): void => {
this.safeRun().passed(test, duration);
this.vscodeRun().passed(test, duration);
};
public skipped = (test: vscode.TestItem): void => {
this.safeRun().skipped(test);
if (!this.ignoreSkipped) {
this.vscodeRun().skipped(test);
}
};
public end = (options?: EndOption): void => {
if (!this._run) {
Expand Down Expand Up @@ -144,4 +154,8 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {
console.log(`JestTestRun "${runName}": TestRun ended because: ${options?.reason}.`);
}
};
// set request for next time the underlying run needed to be created
updateRequest(request: vscode.TestRunRequest): void {
this.request = request;
}
}
2 changes: 2 additions & 0 deletions src/test-provider/test-item-data.ts
Expand Up @@ -64,6 +64,8 @@ abstract class TestItemDataBase implements TestItemData, JestRunnable, WithUri {
if (!this.isTestNameResolved()) {
const parent = this.item.parent && this.context.getData(this.item.parent);
if (parent) {
run.end({ reason: 'unresolved parameterized test' });
run.updateRequest(new vscode.TestRunRequest([parent.item]));
return parent.scheduleTest(run, itemCommand);
}
this.context.output.write(`running an unresolved parameterized test might fail`, 'warn');
Expand Down
8 changes: 1 addition & 7 deletions src/test-provider/test-provider-context.ts
Expand Up @@ -84,13 +84,7 @@ export class JestTestProviderContext {

createTestRun = (request: vscode.TestRunRequest, options?: JestTestRunOptions): JestTestRun => {
const name = options?.name ?? `testRun-${SEQ++}`;
const createRun = (name: string) => {
const vscodeRun = this.controller.createTestRun(request, name);
vscodeRun.appendOutput(`\r\nTestRun "${name}" started\r\n`);
return vscodeRun;
};

return new JestTestRun(name, this, createRun);
return new JestTestRun(name, this, request, this.controller.createTestRun);
};

// tags
Expand Down
1 change: 1 addition & 0 deletions tests/manual-mocks.ts
Expand Up @@ -24,6 +24,7 @@ jest.mock('../src/test-provider/jest-test-run', () => {
write: jest.fn(),
addProcess: jest.fn(),
isClosed: jest.fn(() => false),
updateRequest: jest.fn(),
};
}),
};
Expand Down
68 changes: 52 additions & 16 deletions tests/test-provider/jest-test-runt.test.ts
Expand Up @@ -13,6 +13,7 @@ describe('JestTestRun', () => {
let mockContext: any;
let jestRun: JestTestRun;
let mockCreateTestRun: any;
let mockRequest: any;

beforeEach(() => {
mockContext = {
Expand All @@ -27,19 +28,22 @@ describe('JestTestRun', () => {
},
},
};
mockCreateTestRun = jest.fn().mockImplementation((name: string) => ({
name,
appendOutput: jest.fn(),
enqueued: jest.fn(),
started: jest.fn(),
errored: jest.fn(),
failed: jest.fn(),
passed: jest.fn(),
skipped: jest.fn(),
end: jest.fn(),
}));

jestRun = new JestTestRun('test', mockContext, mockCreateTestRun);
mockCreateTestRun = jest
.fn()
.mockImplementation((_request: vscode.TestRunRequest, name: string) => ({
name,
appendOutput: jest.fn(),
enqueued: jest.fn(),
started: jest.fn(),
errored: jest.fn(),
failed: jest.fn(),
passed: jest.fn(),
skipped: jest.fn(),
end: jest.fn(),
}));

mockRequest = {};
jestRun = new JestTestRun('test', mockContext, mockRequest, mockCreateTestRun);
});

describe('constructor', () => {
Expand Down Expand Up @@ -229,7 +233,7 @@ describe('JestTestRun', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
mockContext.ext.settings.debugMode = true;

jestRun = new JestTestRun('test', mockContext, mockCreateTestRun);
jestRun = new JestTestRun('test', mockContext, mockRequest, mockCreateTestRun);
jestRun.addProcess(pid);
expect(mockCreateTestRun).toHaveBeenCalledTimes(0);

Expand Down Expand Up @@ -294,7 +298,7 @@ describe('JestTestRun', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
mockContext.ext.settings.debugMode = true;

jestRun = new JestTestRun('test', mockContext, mockCreateTestRun);
jestRun = new JestTestRun('test', mockContext, mockRequest, mockCreateTestRun);
jestRun.addProcess(pid);
expect(mockCreateTestRun).toHaveBeenCalledTimes(0);

Expand All @@ -313,7 +317,7 @@ describe('JestTestRun', () => {
it('print warning for runs re-created after close: this means the test-run will be splitted into multiple TestRun', () => {
mockContext.ext.settings.debugMode = true;

jestRun = new JestTestRun('test', mockContext, mockCreateTestRun);
jestRun = new JestTestRun('test', mockContext, mockRequest, mockCreateTestRun);

jestRun.started({} as any);
expect(mockCreateTestRun).toHaveBeenCalledTimes(1);
Expand All @@ -332,4 +336,36 @@ describe('JestTestRun', () => {
const run2 = mockCreateTestRun.mock.results[1].value;
expect(run1).not.toBe(run2);
});
describe('multi-items run', () => {
it('ignore skipped tests if there are more than one test to run', () => {
mockRequest = { include: ['test1', 'test2'] };
jestRun = new JestTestRun('test', mockContext, mockRequest, mockCreateTestRun);

jestRun.started({} as any);
expect(mockCreateTestRun).toHaveBeenCalledTimes(1);
const run = mockCreateTestRun.mock.results[0].value;
expect(run.started).toHaveBeenCalled();

jestRun.skipped({} as any);
expect(run.skipped).not.toHaveBeenCalled();
});
});
describe('when request changed', () => {
it('the next createTestRnn will use the new request', () => {
jestRun = new JestTestRun('test', mockContext, mockRequest, mockCreateTestRun);
jestRun.started({} as any);
expect(mockCreateTestRun).toHaveBeenCalledTimes(1);
const run1 = mockCreateTestRun.mock.results[0].value;
expect(run1.started).toHaveBeenCalled();

jestRun.end();
expect(run1.end).toHaveBeenCalled();

const newRequest: any = { include: ['test1'] };
jestRun.updateRequest(newRequest);
jestRun.started({} as any);
expect(mockCreateTestRun).toHaveBeenCalledTimes(2);
expect(mockCreateTestRun.mock.calls[1][0]).toBe(newRequest);
});
});
});
10 changes: 8 additions & 2 deletions tests/test-provider/test-item-data.test.ts
Expand Up @@ -786,21 +786,27 @@ describe('test-item-data', () => {
expect(process.userData.testItem).toBe(folderData.item);
});
describe('if test name is not resolved', () => {
it('if there is a parent block => will execute it instead', () => {
it('will find the parent block that is resolved to execute instead', () => {
const { doc } = createAllTestItems();
const descNode: any = {
fullName: 'a $describe',
attrs: { nonLiteralName: true },
data: {},
childContainers: [],
childData: [],
};
const testNode: any = { fullName: 'a test', attrs: { isGroup: 'yes' }, data: {} };
const descItem = new TestData(context, doc.uri, descNode, doc.item);
const testItem = new TestData(context, doc.uri, testNode, descItem.item);
const jestRun = createTestRun();

testItem.scheduleTest(jestRun);

expect(process.userData.run).toBe(jestRun);
expect(process.userData.testItem.id).toBe(doc.item.id);

expect(jestRun.end).toHaveBeenCalledTimes(2);
expect(jestRun.updateRequest).toHaveBeenCalledTimes(2);
expect(vscode.TestRunRequest).toHaveBeenLastCalledWith([doc.item]);
});
it('if failed to get parent block, will attempt to run the test anyway', () => {
const { doc } = createAllTestItems();
Expand Down
6 changes: 3 additions & 3 deletions tests/test-provider/test-provider-context.test.ts
Expand Up @@ -28,13 +28,13 @@ describe('JestTestProviderContext', () => {
const jestRun = context.createTestRun(request, { name: 'test-run' });

expect(jestRun).toBe(mockJestRun);
expect(JestTestRun).toHaveBeenCalledWith('test-run', context, expect.anything());
expect(JestTestRun).toHaveBeenCalledWith('test-run', context, request, expect.anything());
// no vscode run should be created yet
expect(mockController.createTestRun).not.toHaveBeenCalled();

// vscode run will be created through the factory function
const factory = (JestTestRun as jest.Mocked<any>).mock.calls[0][2];
const run = factory('new-test-run');
const factory = (JestTestRun as jest.Mocked<any>).mock.calls[0][3];
const run = factory(request, 'new-test-run');

expect(mockController.createTestRun).toHaveBeenCalledWith(request, 'new-test-run');
expect(run).toBe(mockRun);
Expand Down
2 changes: 1 addition & 1 deletion tests/test-provider/test-provider.test.ts
Expand Up @@ -115,7 +115,7 @@ describe('JestTestProvider', () => {

describe('can discover tests', () => {
it('test mockedJestTestRun', () => {
const jestRun = new JestTestRun('jest-run', {} as any, (() => {}) as any);
const jestRun = new JestTestRun('jest-run', {} as any, {} as any, (() => {}) as any);
expect(jestRun.name).toBe('jest-run');
});
it('should only discover items with canResolveChildren = true', () => {
Expand Down

0 comments on commit abfe69f

Please sign in to comment.