<commit_before>import { remote } from 'webdriverio';
import Mugshot from 'mugshot';
import WebdriverIOAdapter from 'mugshot-webdriverio';
import path from 'path';
import fs from 'fs';
import { expect } from 'chai';
import {
  runnerAfter,
  runnerBefore,
  runnerBeforeEach,
  runnerIt,
  runnerDescribe
} from './test-runner.js';

const { BROWSER = 'chrome', SELENIUM_HOST = 'selenium' } = process.env;

let suiteNesting = 0;

// These will hold root suite level instances. Since most, if not all test
// runners run tests inside of a suite sequentially and since we only set
// up the browser once per root test suite, these should be "thread safe".
let rootSuiteBrowser, rootSuiteMugshot;

/**
 * Run your acceptance tests in a fresh Selenium session.
 *
 * Nested calls will preserve the root session.
 *
 * Tests and hooks will receive the browser instance.
 *
 * @param {String} name
 * @param {() => void} definition
 */
export function describe(name, definition) {
  suiteNesting++;

  runnerDescribe(name, function() {
    // We only want to set up hooks once - for the root suite.
    suiteNesting === 1 && setupHooks();

    definition();
  });

  suiteNesting--;
}

/**
 * @param {(Webdriver) => Promise} definition
 */
export function beforeEach(definition) {
  runnerBeforeEach(function() {
    return definition(rootSuiteBrowser);
  });
}

/**
 * Run a test with optional coverage report.
 *
 * @param {String} name
 * @param {(Webdriver) => Promise|undefined} definition
 */
export function it(name, definition) {
  runnerIt(name, function() {
    const promise = Promise.resolve(definition(rootSuiteBrowser));
    const testName = this.test.fullTitle();

    if (process.env.NODE_ENV !== 'tests') {
      return promise;
    }

    return promise.then(() => collectCoverage(testName));
  });
}

/**
 * Perform a visual test alongside a normal test.
 *
 * The visual test will not be performed if the test in `definition` fails.
 *
 * @param {String} name The name of the test. The screenshot will be taken under
 *   the full test name (including any parent suite's name(s)).
 * @param {(Webdriver) => Promise|undefined} definition
 * @param {CSSSelector} selector
 */
export function vit(name, definition, selector = '.todoapp') {
  runnerIt(name, function() {
    const promise = Promise.resolve(definition(rootSuiteBrowser));
    const testName = getSafeFilename(this.test.fullTitle());

    // Don't want to make debugging tests more noisy than it needs to be.
    if (!process.env.DEBUG) {
      promise = promise.then(() => checkForVisualChanges(testName, selector));
    }

    if (process.env.NODE_ENV === 'tests') {
      promise.then(() => collectCoverage(testName));<commit_msg>Wait for the whole promise chain in visual tests<commit_after>import { remote } from 'webdriverio';
import Mugshot from 'mugshot';
import WebdriverIOAdapter from 'mugshot-webdriverio';
import path from 'path';
import fs from 'fs';
import { expect } from 'chai';
import {
  runnerAfter,
  runnerBefore,
  runnerBeforeEach,
  runnerIt,
  runnerDescribe
} from './test-runner.js';

const { BROWSER = 'chrome', SELENIUM_HOST = 'selenium' } = process.env;

let suiteNesting = 0;

// These will hold root suite level instances. Since most, if not all test
// runners run tests inside of a suite sequentially and since we only set
// up the browser once per root test suite, these should be "thread safe".
let rootSuiteBrowser, rootSuiteMugshot;

/**
 * Run your acceptance tests in a fresh Selenium session.
 *
 * Nested calls will preserve the root session.
 *
 * Tests and hooks will receive the browser instance.
 *
 * @param {String} name
 * @param {() => void} definition
 */
export function describe(name, definition) {
  suiteNesting++;

  runnerDescribe(name, function() {
    // We only want to set up hooks once - for the root suite.
    suiteNesting === 1 && setupHooks();

    definition();
  });

  suiteNesting--;
}

/**
 * @param {(Webdriver) => Promise} definition
 */
export function beforeEach(definition) {
  runnerBeforeEach(function() {
    return definition(rootSuiteBrowser);
  });
}

/**
 * Run a test with optional coverage report.
 *
 * @param {String} name
 * @param {(Webdriver) => Promise|undefined} definition
 */
export function it(name, definition) {
  runnerIt(name, function() {
    const promise = Promise.resolve(definition(rootSuiteBrowser));
    const testName = this.test.fullTitle();

    if (process.env.NODE_ENV !== 'tests') {
      return promise;
    }

    return promise.then(() => collectCoverage(testName));
  });
}

/**
 * Perform a visual test alongside a normal test.
 *
 * The visual test will not be performed if the test in `definition` fails.
 *
 * @param {String} name The name of the test. The screenshot will be taken under
 *   the full test name (including any parent suite's name(s)).
 * @param {(Webdriver) => Promise|undefined} definition
 * @param {CSSSelector} selector
 */
export function vit(name, definition, selector = '.todoapp') {
  runnerIt(name, function() {
    let promise = Promise.resolve(definition(rootSuiteBrowser));
    const testName = getSafeFilename(this.test.fullTitle());

    // Don't want to make debugging tests more noisy than it needs to be.
    if (!process.env.DEBUG) {
      promise = promise.then(() => checkForVisualChanges(testName, selector));
    }

    if (process.env.NODE_ENV === 'tests') {
      promise = promise.then(() => collectCoverage(testName));
{'fraction_non_alphanumeric': 0.12227314390467461, 'fraction_numerical': 0.0007332722273143905, 'mean_word_length': 3.8670829616413918, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '892034', 'n_tokens_mistral': 1589, 'n_tokens_neox': 1538, 'n_words': 548}