From f1040a68a75d3fafe0f564595b7a898b232271fd Mon Sep 17 00:00:00 2001 From: Paul LeMarquand Date: Thu, 31 Oct 2024 10:26:15 -0400 Subject: [PATCH] Fix improper test argument simplification If the user tried to run a test suite that had as many tests as there are test suites in the module we improperly simplified the test arguments to run all suites in the module. This patch fixes this behaviour, and also introduces more robust tests. Issue: #1183 --- src/TestExplorer/TestRunArguments.ts | 147 +++---- .../testexplorer/TestRunArguments.test.ts | 373 ++++++++++++------ 2 files changed, 341 insertions(+), 179 deletions(-) diff --git a/src/TestExplorer/TestRunArguments.ts b/src/TestExplorer/TestRunArguments.ts index b0d4fe811..413acbee7 100644 --- a/src/TestExplorer/TestRunArguments.ts +++ b/src/TestExplorer/TestRunArguments.ts @@ -17,8 +17,8 @@ import { reduceTestItemChildren } from "./TestUtils"; type ProcessResult = { testItems: vscode.TestItem[]; - xcTestArgs: string[]; - swiftTestArgs: string[]; + xcTestArgs: vscode.TestItem[]; + swiftTestArgs: vscode.TestItem[]; }; /** @@ -30,14 +30,11 @@ export class TestRunArguments { public xcTestArgs: string[]; public swiftTestArgs: string[]; - constructor( - request: vscode.TestRunRequest, - private isDebug: boolean - ) { - const { testItems, xcTestArgs, swiftTestArgs } = this.createTestLists(request); + constructor(request: vscode.TestRunRequest, isDebug: boolean) { + const { testItems, xcTestArgs, swiftTestArgs } = this.createTestLists(request, isDebug); this.testItems = testItems; - this.xcTestArgs = xcTestArgs; - this.swiftTestArgs = swiftTestArgs; + this.xcTestArgs = this.annotateTestArgs(xcTestArgs, isDebug); + this.swiftTestArgs = this.annotateTestArgs(swiftTestArgs, isDebug); } public get hasXCTests(): boolean { @@ -52,9 +49,10 @@ export class TestRunArguments { * Construct test item list from TestRequest * @returns list of test items to run and list of test for XCTest arguments */ - private createTestLists(request: vscode.TestRunRequest): ProcessResult { + private createTestLists(request: vscode.TestRunRequest, isDebug: boolean): ProcessResult { const includes = request.include ?? []; - return includes.reduce(this.createTestItemReducer(request.include, request.exclude), { + const excludes = request.exclude ?? []; + return includes.reduce(this.createTestItemReducer(includes, excludes, isDebug), { testItems: this.createIncludeParentList(includes), xcTestArgs: [], swiftTestArgs: [], @@ -78,15 +76,42 @@ export class TestRunArguments { return Array.from(parents.values()); } + /** + * Converts a list of TestItems to a regex test item ID. Depending on the TestItem's + * tags and whether it is a debug run the ID is converted to a regex pattern that will + * match the correct tests when passed to the `--filter` argument of `swift test`. + */ + private annotateTestArgs(testArgs: vscode.TestItem[], isDebug: boolean): string[] { + return testArgs.map(arg => { + const isTestTarget = !!arg.tags.find(tag => tag.id === "test-target"); + if (isTestTarget) { + return `${arg.id}.*`; + } + const isXCTest = !!arg.tags.find(tag => tag.id === "XCTest"); + const hasChildren = arg.children.size > 0; + if (isXCTest) { + const terminator = hasChildren ? "/" : "$"; + // Debugging XCTests requires exact matches, so we don't need a trailing terminator. + return isDebug ? arg.id : `${arg.id}${terminator}`; + } else { + // Append a trailing slash to match a suite name exactly. + // This prevents TestTarget.MySuite matching TestTarget.MySuite2. + return `${arg.id}/`; + } + }); + } + private createTestItemReducer( - include: readonly vscode.TestItem[] | undefined, - exclude: readonly vscode.TestItem[] | undefined + include: readonly vscode.TestItem[], + exclude: readonly vscode.TestItem[], + isDebug: boolean ): (previousValue: ProcessResult, testItem: vscode.TestItem) => ProcessResult { return (previousValue, testItem) => { const { testItems, swiftTestArgs, xcTestArgs } = this.processTestItem( testItem, include, - exclude + exclude, + isDebug ); // If no children were added we can skip adding this parent. @@ -119,63 +144,53 @@ export class TestRunArguments { private itemContainsAllArgs( testItem: vscode.TestItem, - xcTestArgs: string[], - swiftTestArgs: string[] + xcTestArgs: vscode.TestItem[], + swiftTestArgs: vscode.TestItem[] ): boolean { - return xcTestArgs.length + swiftTestArgs.length === testItem.children.size; + return ( + testItem.children.size > 0 && + xcTestArgs.length + swiftTestArgs.length === testItem.children.size + ); } private simplifyTestArgs( testItem: vscode.TestItem, - xcTestArgs: string[], - swiftTestArgs: string[] - ): { xcTestResult: string[]; swiftTestResult: string[] } { - if ( - testItem.parent && - this.itemContainsAllArgs(testItem.parent, xcTestArgs, swiftTestArgs) - ) { - return this.simplifyTestArgs(testItem.parent, xcTestArgs, swiftTestArgs); - } else { - // If we've worked all the way up to a test target, it may have both swift-testing - // and XCTests. - const isTestTarget = !!testItem.tags.find(tag => tag.id === "test-target"); - if (isTestTarget) { - return { - // Add a trailing .* to match a test target name exactly. - // This prevents TestTarget matching TestTarget2. - xcTestResult: xcTestArgs.length > 0 ? [`${testItem.id}.*`] : [], - swiftTestResult: swiftTestArgs.length > 0 ? [`${testItem.id}.*`] : [], - }; - } - - // If we've added all the children to the list of arguments, just add - // the parent instead of each individual child. This crafts a minimal set - // of test/suites that run all the test cases requested with the smallest list - // of arguments. The testItem has to have a parent to perform this optimization. - // If it does not we break the ability to run both swift testing tests and XCTests - // in the same run, since test targets can have both types of tests in them. - const isXCTest = !!testItem.tags.find(tag => tag.id === "XCTest"); + xcTestArgs: vscode.TestItem[], + swiftTestArgs: vscode.TestItem[] + ): { xcTestResult: vscode.TestItem[]; swiftTestResult: vscode.TestItem[] } { + // If we've worked all the way up to a test target, it may have both swift-testing + // and XCTests. + const isTestTarget = !!testItem.tags.find(tag => tag.id === "test-target"); + if (isTestTarget) { return { - swiftTestResult: [ - // Append a trailing slash to match a suite name exactly. - // This prevents TestTarget.MySuite matching TestTarget.MySuite2. - ...(!isXCTest ? [`${testItem.id}/`] : []), - ], - xcTestResult: [ - // Debugging XCTests require exact matches, so we don't ned a trailing slash. - ...(isXCTest ? [this.isDebug ? testItem.id : `${testItem.id}/`] : []), - ], + // Add a trailing .* to match a test target name exactly. + // This prevents TestTarget matching TestTarget2. + xcTestResult: xcTestArgs.length > 0 ? [testItem] : [], + swiftTestResult: swiftTestArgs.length > 0 ? [testItem] : [], }; } + + // If we've added all the children to the list of arguments, just add + // the parent instead of each individual child. This crafts a minimal set + // of test/suites that run all the test cases requested with the smallest list + // of arguments. The testItem has to have a parent to perform this optimization. + // If it does not we break the ability to run both swift testing tests and XCTests + // in the same run, since test targets can have both types of tests in them. + const isXCTest = !!testItem.tags.find(tag => tag.id === "XCTest"); + return { + xcTestResult: isXCTest ? [testItem] : [], + swiftTestResult: !isXCTest ? [testItem] : [], + }; } private processTestItem( testItem: vscode.TestItem, - include?: readonly vscode.TestItem[], - exclude?: readonly vscode.TestItem[] + include: readonly vscode.TestItem[], + exclude: readonly vscode.TestItem[], + isDebug: boolean ): ProcessResult { // Skip tests the user asked to exclude - if (exclude?.includes(testItem)) { + if (exclude.includes(testItem)) { return { testItems: [], xcTestArgs: [], @@ -184,12 +199,13 @@ export class TestRunArguments { } const testItems: vscode.TestItem[] = []; - const xcTestArgs: string[] = []; - const swiftTestArgs: string[] = []; + const xcTestArgs: vscode.TestItem[] = []; + const swiftTestArgs: vscode.TestItem[] = []; // If this test item is included or we are including everything - if (include?.includes(testItem) || !include) { + if (include.includes(testItem) || include.length === 0) { const isXCTest = testItem.tags.find(tag => tag.id === "XCTest"); + const isSwiftTestingTest = testItem.tags.find(tag => tag.id === "swift-testing"); // Collect up a list of all the test items involved in the run // from the TestExplorer tree and store them in `testItems`. Exclude @@ -200,12 +216,9 @@ export class TestRunArguments { // Only add leaf items to the list of arguments to pass to the test runner. if (this.isLeafTestItem(testItem, !!isXCTest)) { if (isXCTest) { - // Tests in debug are specified exactly, otherwise - // add the regex line ending character to avoid capturing - // unwanted tests. - xcTestArgs.push(this.isDebug ? testItem.id : `${testItem.id}$`); - } else { - swiftTestArgs.push(testItem.id); + xcTestArgs.push(testItem); + } else if (isSwiftTestingTest) { + swiftTestArgs.push(testItem); } } } @@ -213,7 +226,7 @@ export class TestRunArguments { return reduceTestItemChildren( testItem.children, - this.createTestItemReducer(undefined, exclude), + this.createTestItemReducer([], exclude, isDebug), { testItems, xcTestArgs, diff --git a/test/integration-tests/testexplorer/TestRunArguments.test.ts b/test/integration-tests/testexplorer/TestRunArguments.test.ts index 98f63f844..9dc660c11 100644 --- a/test/integration-tests/testexplorer/TestRunArguments.test.ts +++ b/test/integration-tests/testexplorer/TestRunArguments.test.ts @@ -16,152 +16,301 @@ import * as vscode from "vscode"; import * as assert from "assert"; import { beforeEach } from "mocha"; import { TestRunArguments } from "../../../src/TestExplorer/TestRunArguments"; +import { flattenTestItemCollection } from "../../../src/TestExplorer/TestUtils"; suite("TestRunArguments Suite", () => { + // Helper function to create a test item tree from a DSL string. + // Tabs are used to denote a hierarchy of test items. + function createTestItemTree(controller: vscode.TestController, dsl: string) { + const lines = dsl.trim().split("\n"); + const stack: { item: vscode.TestItem; indent: number }[] = []; + let root: vscode.TestItem | undefined; + + lines.forEach(line => { + const indent = line.search(/\S/); + const trimmedLine = line.trim(); + const name = trimmedLine.replace(/^(tt:|xc:|st:)/, ""); + const tags = []; + if (trimmedLine.startsWith("tt:")) { + tags.push({ id: "test-target" }); + } else if (trimmedLine.startsWith("xc:")) { + tags.push({ id: "XCTest" }); + } else if (trimmedLine.startsWith("st:")) { + tags.push({ id: "swift-testing" }); + } + const item = controller.createTestItem(name, name, vscode.Uri.file("/path/to/file")); + item.tags = tags; + + while (stack.length && stack[stack.length - 1].indent >= indent) { + stack.pop(); + } + + if (stack.length) { + stack[stack.length - 1].item.children.add(item); + } else { + root = item; + } + + stack.push({ item, indent }); + }); + + controller.items.add(root!); + } + + function runRequestByIds(include: string[], exclude: string[] = []) { + const allTests = flattenTestItemCollection(controller.items); + const includeItems = include.map(id => allTests.find(item => item.id === id)); + const excludeItems = exclude.map(id => allTests.find(item => item.id === id)); + if (includeItems.some(item => !item)) { + throw new Error("Could not find test item in include list: " + include); + } + if (excludeItems.some(item => !item)) { + throw new Error("Could not find test item in exclude list: " + include); + } + return new vscode.TestRunRequest( + includeItems as vscode.TestItem[], + excludeItems as vscode.TestItem[], + undefined + ); + } + + function assertRunArguments( + args: TestRunArguments, + expected: Omit< + Omit, "hasXCTests">, + "hasSwiftTestingTests" + > & { testItems: string[] } + ) { + // Order of testItems doesn't matter, that they contain the same elements. + assert.deepStrictEqual( + { ...args, testItems: args.testItems.map(item => item.id).sort() }, + { ...expected, testItems: expected.testItems.sort() } + ); + } + let controller: vscode.TestController; - let testTarget: vscode.TestItem; - let xcSuite: vscode.TestItem; - let xcTest: vscode.TestItem; - let swiftTestSuite: vscode.TestItem; - let swiftTest: vscode.TestItem; + const testTargetId: string = "TestTarget"; + const xcSuiteId: string = "XCTest Suite"; + const xcTestId: string = "XCTest Item"; + const swiftTestSuiteId: string = "Swift Test Suite"; + const swiftTestId: string = "Swift Test Item"; beforeEach(function () { controller = vscode.tests.createTestController( this.currentTest?.id ?? "TestRunArgumentsTests", "" ); + }); - testTarget = controller.createTestItem("TestTarget", "TestTarget"); - testTarget.tags = [{ id: "test-target" }]; + suite("Basic Tests", () => { + beforeEach(() => { + const dsl = ` + tt:${testTargetId} + xc:${xcSuiteId} + xc:${xcTestId} + st:${swiftTestSuiteId} + st:${swiftTestId} + `; - controller.items.add(testTarget); + createTestItemTree(controller, dsl); + }); - xcSuite = controller.createTestItem( - "XCTest Suite", - "XCTest Suite", - vscode.Uri.file("/path/to/file") - ); - xcSuite.tags = [{ id: "XCTest" }]; + test("Empty Request", () => { + const testArgs = new TestRunArguments(runRequestByIds([]), false); + assertRunArguments(testArgs, { + xcTestArgs: [], + swiftTestArgs: [], + testItems: [], + }); + }); - testTarget.children.add(xcSuite); + test("Test hasTestType methods", () => { + const xcTest = new TestRunArguments(runRequestByIds([xcTestId]), false); + const swiftTestingTest = new TestRunArguments(runRequestByIds([swiftTestId]), false); + const bothTests = new TestRunArguments(runRequestByIds([xcTestId, swiftTestId]), false); + assert.strictEqual(xcTest.hasXCTests, true); + assert.strictEqual(xcTest.hasSwiftTestingTests, false); + assert.strictEqual(swiftTestingTest.hasXCTests, false); + assert.strictEqual(swiftTestingTest.hasSwiftTestingTests, true); + assert.strictEqual(bothTests.hasXCTests, true); + assert.strictEqual(bothTests.hasSwiftTestingTests, true); + }); - xcTest = controller.createTestItem( - "XCTest Item", - "XCTest Item", - vscode.Uri.file("/path/to/file") - ); - xcTest.tags = [{ id: "XCTest" }]; + test("Single XCTest", () => { + const testArgs = new TestRunArguments(runRequestByIds([xcTestId]), false); + assertRunArguments(testArgs, { + xcTestArgs: [`${xcTestId}$`], + swiftTestArgs: [], + testItems: [xcSuiteId, testTargetId, xcTestId], + }); + }); - xcSuite.children.add(xcTest); + test("Single XCTest (debug mode)", () => { + const testArgs = new TestRunArguments(runRequestByIds([xcTestId]), true); + assertRunArguments(testArgs, { + xcTestArgs: [xcTestId], + swiftTestArgs: [], + testItems: [xcSuiteId, testTargetId, xcTestId], + }); + }); - swiftTestSuite = controller.createTestItem( - "Swift Test Suite", - "Swift Test Suite", - vscode.Uri.file("/path/to/file") - ); - swiftTestSuite.tags = [{ id: "swift-testing" }]; + test("Both Suites Included", () => { + const testArgs = new TestRunArguments( + runRequestByIds([xcSuiteId, swiftTestSuiteId]), + false + ); + assertRunArguments(testArgs, { + xcTestArgs: [`${xcSuiteId}/`], + swiftTestArgs: [`${swiftTestSuiteId}/`], + testItems: [testTargetId, xcSuiteId, xcTestId, swiftTestSuiteId, swiftTestId], + }); + }); - testTarget.children.add(swiftTestSuite); + test("Exclude Suite", () => { + const testArgs = new TestRunArguments( + runRequestByIds([xcSuiteId, swiftTestSuiteId], [xcSuiteId]), + false + ); + assertRunArguments(testArgs, { + xcTestArgs: [], + swiftTestArgs: [`${swiftTestSuiteId}/`], + testItems: [testTargetId, swiftTestSuiteId, swiftTestId], + }); + }); - swiftTest = controller.createTestItem( - "Swift Test Item", - "Swift Test Item", - vscode.Uri.file("/path/to/file") - ); - swiftTest.tags = [{ id: "swift-testing" }]; + test("Exclude Test", () => { + const testArgs = new TestRunArguments( + runRequestByIds([xcSuiteId, swiftTestSuiteId], [xcTestId]), + false + ); + assertRunArguments(testArgs, { + xcTestArgs: [], + swiftTestArgs: [`${swiftTestSuiteId}/`], + testItems: [testTargetId, swiftTestSuiteId, swiftTestId], + }); + }); - swiftTestSuite.children.add(swiftTest); + test("Entire test target", () => { + const testArgs = new TestRunArguments(runRequestByIds([testTargetId], []), false); + assertRunArguments(testArgs, { + xcTestArgs: [`${testTargetId}.*`], + swiftTestArgs: [`${testTargetId}.*`], + testItems: [testTargetId, xcSuiteId, xcTestId, swiftTestSuiteId, swiftTestId], + }); + }); }); - test("Empty Request", () => { - const testArgs = new TestRunArguments( - new vscode.TestRunRequest([], undefined, undefined), - false - ); - assert.equal(testArgs.hasXCTests, false); - assert.equal(testArgs.hasSwiftTestingTests, false); + test("Test empty test target", () => { + createTestItemTree(controller, `tt:${testTargetId}`); + const testArgs = new TestRunArguments(runRequestByIds([testTargetId], []), false); + assertRunArguments(testArgs, { + xcTestArgs: [], + swiftTestArgs: [], + testItems: [], + }); }); - test("Both Suites Included", () => { - const testArgs = new TestRunArguments( - new vscode.TestRunRequest([xcSuite, swiftTestSuite], undefined, undefined), - false - ); - assert.equal(testArgs.hasXCTests, true); - assert.equal(testArgs.hasSwiftTestingTests, true); - assert.deepEqual(testArgs.xcTestArgs, [`${xcSuite.id}/`]); - assert.deepEqual(testArgs.swiftTestArgs, [`${swiftTestSuite.id}/`]); - assert.deepEqual( - testArgs.testItems.map(item => item.id), - [testTarget.id, xcSuite.id, xcTest.id, swiftTestSuite.id, swiftTest.id] - ); + test("Test undefined include/exclude", () => { + createTestItemTree(controller, `tt:${testTargetId}`); + const testArgs = new TestRunArguments(new vscode.TestRunRequest(), false); + assertRunArguments(testArgs, { + xcTestArgs: [], + swiftTestArgs: [], + testItems: [], + }); }); - test("Exclude Suite", () => { - const testArgs = new TestRunArguments( - new vscode.TestRunRequest([xcSuite, swiftTestSuite], [xcSuite], undefined), - false - ); - assert.equal(testArgs.hasXCTests, false); - assert.equal(testArgs.hasSwiftTestingTests, true); - assert.deepEqual(testArgs.xcTestArgs, []); - assert.deepEqual(testArgs.swiftTestArgs, [`${swiftTestSuite.id}/`]); - assert.deepEqual( - testArgs.testItems.map(item => item.id), - [testTarget.id, swiftTestSuite.id, swiftTest.id] - ); + test("Single Test in Suite With Multiple", () => { + const anotherSwiftTestId = "Another Swift Test Item"; + const dsl = ` + tt:${testTargetId} + xc:${xcSuiteId} + xc:${xcTestId} + st:${swiftTestSuiteId} + st:${swiftTestId} + st:${anotherSwiftTestId} + `; + + createTestItemTree(controller, dsl); + + const testArgs = new TestRunArguments(runRequestByIds([anotherSwiftTestId]), false); + assertRunArguments(testArgs, { + xcTestArgs: [], + swiftTestArgs: [`${anotherSwiftTestId}/`], + testItems: [swiftTestSuiteId, testTargetId, anotherSwiftTestId], + }); }); - test("Exclude Test", () => { - const testArgs = new TestRunArguments( - new vscode.TestRunRequest([xcSuite, swiftTestSuite], [xcTest], undefined), - false - ); - assert.equal(testArgs.hasXCTests, false); - assert.equal(testArgs.hasSwiftTestingTests, true); - assert.deepEqual(testArgs.xcTestArgs, []); - assert.deepEqual(testArgs.swiftTestArgs, [`${swiftTestSuite.id}/`]); - assert.deepEqual( - testArgs.testItems.map(item => item.id), - [testTarget.id, swiftTestSuite.id, swiftTest.id] - ); + test("Test suite with multiple suites of different sizes", () => { + const anotherXcSuiteId = "Another XCTest Suite"; + const anotherXcTestId1 = "Another XCTest Item 1"; + const anotherXcTestId2 = "Another XCTest Item 2"; + const dsl = ` + tt:${testTargetId} + xc:${xcSuiteId} + xc:${xcTestId} + xc:${anotherXcSuiteId} + xc:${anotherXcTestId1} + xc:${anotherXcTestId2} + `; + createTestItemTree(controller, dsl); + + const testArgs = new TestRunArguments(runRequestByIds([xcSuiteId], []), false); + assertRunArguments(testArgs, { + xcTestArgs: [`${xcSuiteId}/`], + swiftTestArgs: [], + testItems: [testTargetId, xcSuiteId, xcTestId], + }); }); - test("Single Test in Suite With Multiple", () => { - const anotherSwiftTest = controller.createTestItem( - "Another Swift Test Item", - "Another Swift Test Item", - vscode.Uri.file("/path/to/file") - ); - anotherSwiftTest.tags = [{ id: "swift-testing" }]; - swiftTestSuite.children.add(anotherSwiftTest); + test("Test suite with multiple suites of the same size", () => { + const xcTestId2 = "XCTest Item 2"; + const anotherXcSuiteId = "Another XCTest Suite"; + const anotherXcTestId1 = "Another XCTest Item 1"; + const anotherXcTestId2 = "Another XCTest Item 2"; + const dsl = ` + tt:${testTargetId} + xc:${xcSuiteId} + xc:${xcTestId} + xc:${xcTestId2} + xc:${anotherXcSuiteId} + xc:${anotherXcTestId1} + xc:${anotherXcTestId2} + `; + createTestItemTree(controller, dsl); - const testArgs = new TestRunArguments( - new vscode.TestRunRequest([anotherSwiftTest], [], undefined), - false - ); - assert.equal(testArgs.hasXCTests, false); - assert.equal(testArgs.hasSwiftTestingTests, true); - assert.deepEqual(testArgs.xcTestArgs, []); - assert.deepEqual(testArgs.swiftTestArgs, [anotherSwiftTest.id]); - assert.deepEqual( - testArgs.testItems.map(item => item.id), - [swiftTestSuite.id, testTarget.id, anotherSwiftTest.id] - ); + const testArgs = new TestRunArguments(runRequestByIds([xcSuiteId], []), false); + assertRunArguments(testArgs, { + xcTestArgs: [`${xcSuiteId}/`], + swiftTestArgs: [], + testItems: [testTargetId, xcSuiteId, xcTestId, xcTestId2], + }); }); - test("Entire test target", () => { + test("Test multiple tests across suites", () => { + const xcTestId2 = "XCTest Item 2"; + const anotherXcSuiteId = "Another XCTest Suite"; + const anotherXcTestId1 = "Another XCTest Item 1"; + const anotherXcTestId2 = "Another XCTest Item 2"; + const dsl = ` + tt:${testTargetId} + xc:${xcSuiteId} + xc:${xcTestId} + xc:${xcTestId2} + xc:${anotherXcSuiteId} + xc:${anotherXcTestId1} + xc:${anotherXcTestId2} + `; + createTestItemTree(controller, dsl); + const testArgs = new TestRunArguments( - new vscode.TestRunRequest([testTarget], [], undefined), + runRequestByIds([xcTestId, anotherXcTestId1], []), false ); - assert.equal(testArgs.hasXCTests, true); - assert.equal(testArgs.hasSwiftTestingTests, true); - assert.deepEqual(testArgs.xcTestArgs, [`${testTarget.id}.*`]); - assert.deepEqual(testArgs.swiftTestArgs, [`${testTarget.id}.*`]); - assert.deepEqual( - testArgs.testItems.map(item => item.id), - [xcSuite.id, xcTest.id, swiftTestSuite.id, swiftTest.id] - ); + assertRunArguments(testArgs, { + xcTestArgs: [`${xcTestId}$`, `${anotherXcTestId1}$`], + swiftTestArgs: [], + testItems: [testTargetId, xcSuiteId, xcTestId, anotherXcSuiteId, anotherXcTestId1], + }); }); });