Repository: microsoft/playwright
File: packages/playwright/src/runner/testRunner.ts (TypeScript)

Code before:
      retries: 0,
      timeout: params.timeout,
      preserveOutputDir: true,
      reporter: params.reporters ? params.reporters.map(r => [r]) : undefined,
      use: {
        ...this._configCLIOverrides.use,
        ...(params.trace === 'on' ? { trace: { mode: 'on', sources: false, _live: true } } : {}),
        ...(params.trace === 'off' ? { trace: 'off' } : {}),
        ...(params.video === 'on' || params.video === 'off' ? { video: params.video } : {}),
        ...(params.headed !== undefined ? { headless: !params.headed } : {}),
        _optionContextReuseMode: params.reuseContext ? 'when-possible' : undefined,
        _optionConnectOptions: params.connectWsEndpoint ? { wsEndpoint: params.connectWsEndpoint } : undefined,
        actionTimeout: params.actionTimeout,
      },
      ...(params.updateSnapshots ? { updateSnapshots: params.updateSnapshots } : {}),
      ...(params.updateSourceMethod ? { updateSourceMethod: params.updateSourceMethod } : {}),
      ...(params.workers ? { workers: params.workers } : {}),
    };

    const config = await this._loadConfigOrReportError(new InternalReporter([userReporter]), overrides);
    if (!config)
      return { status: 'failed' };

    config.cliListOnly = false;
    config.cliPassWithNoTests = true;
    config.cliArgs = params.locations ?? ['dont-match-anything']; // for performance reasons, we require test runner users to pass `locations`. they can opt out by passing [].
    config.cliGrep = params.grep;
    config.cliGrepInvert = params.grepInvert;
    config.cliProjectFilter = params.projects?.length ? params.projects : undefined;
    config.preOnlyTestFilters = [];
    if (params.testIds) {
      const testIdSet = new Set<string>(params.testIds);
      config.preOnlyTestFilters.push(test => testIdSet.has(test.id));
    }

    const configReporters = params.disableConfigReporters ? [] : await createReporters(config, 'test');
    const reporter = new InternalReporter([...configReporters, userReporter]);
    const stop = new ManualPromise();
    const tasks = [
      createApplyRebaselinesTask(),
      createLoadTask('out-of-process', { filterOnly: true, failOnLoadErrors: !!params.failOnLoadErrors, doNotRunDepsOutsideProjectFilter: params.doNotRunDepsOutsideProjectFilter }),
      ...createRunTestsTasks(config),
    ];
    const testRun = new TestRun(config, reporter, { pauseOnError: params.pauseOnError, pauseAtEnd: params.pauseAtEnd });
    testRun.failureTracker.onTestPaused = params => this.emit(TestRunnerEvent.TestPaused, params);
    const run = runTasks(testRun, tasks, 0, stop).then(async status => {
      this._testRun = undefined;
      return status;
    });
    this._testRun = { run, stop };
    return { status: await run };

Review comment (suggestion):
If we require passing locations, let's make them required in the type, instead of using `dont-match-anything` hack.

Code after:
      retries: 0,
      timeout: params.timeout,
      preserveOutputDir: true,
      reporter: params.reporters ? params.reporters.map(r => [r]) : undefined,
      use: {
        ...this._configCLIOverrides.use,
        ...(params.trace === 'on' ? { trace: { mode: 'on', sources: false, _live: true } } : {}),
        ...(params.trace === 'off' ? { trace: 'off' } : {}),
        ...(params.video === 'on' || params.video === 'off' ? { video: params.video } : {}),
        ...(params.headed !== undefined ? { headless: !params.headed } : {}),
        _optionContextReuseMode: params.reuseContext ? 'when-possible' : undefined,
        _optionConnectOptions: params.connectWsEndpoint ? { wsEndpoint: params.connectWsEndpoint } : undefined,
        actionTimeout: params.actionTimeout,
      },
      ...(params.updateSnapshots ? { updateSnapshots: params.updateSnapshots } : {}),
      ...(params.updateSourceMethod ? { updateSourceMethod: params.updateSourceMethod } : {}),
      ...(params.workers ? { workers: params.workers } : {}),
    };

    const config = await this._loadConfigOrReportError(new InternalReporter([userReporter]), overrides);
    if (!config)
      return { status: 'failed' };

    config.cliListOnly = false;
    config.cliPassWithNoTests = true;
    config.cliArgs = params.locations;
    config.cliGrep = params.grep;
    config.cliGrepInvert = params.grepInvert;
    config.cliProjectFilter = params.projects?.length ? params.projects : undefined;
    config.preOnlyTestFilters = [];
    if (params.testIds) {
      const testIdSet = new Set<string>(params.testIds);
      config.preOnlyTestFilters.push(test => testIdSet.has(test.id));
    }

    const configReporters = params.disableConfigReporters ? [] : await createReporters(config, 'test');
    const reporter = new InternalReporter([...configReporters, userReporter]);
    const stop = new ManualPromise();
    const tasks = [
      createApplyRebaselinesTask(),
      createLoadTask('out-of-process', { filterOnly: true, failOnLoadErrors: !!params.failOnLoadErrors, doNotRunDepsOutsideProjectFilter: params.doNotRunDepsOutsideProjectFilter }),
      ...createRunTestsTasks(config),
    ];
    const testRun = new TestRun(config, reporter, { pauseOnError: params.pauseOnError, pauseAtEnd: params.pauseAtEnd });
    testRun.failureTracker.onTestPaused = params => this.emit(TestRunnerEvent.TestPaused, params);
    const run = runTasks(testRun, tasks, 0, stop).then(async status => {
      this._testRun = undefined;
      return status;
    });
    this._testRun = { run, stop };
    return { status: await run };