mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 12:51:55 +00:00
chore(ci): remove Percy visual tests (#63515)
These are more frequently erroneous than helpful. See https://sourcegraph.slack.com/archives/C04MYFW01NV/p1719209633005499. This eliminates a source of frustration and flakiness in pull requests and removes a lot of code and Bazel complexity. If we want to revive them, we can revert this commit. Note that `client/web-sveltekit` does not use Percy, and if we want it to, we can always revert this commit or start over from scratch if that's easier. <!-- PR description tips: https://www.notion.so/sourcegraph/Write-a-good-pull-request-description-610a7fd3e613496eb76f450db5a49b6e --> ## Test plan CI Co-authored-by: Jean-Hadrien Chabran <jean-hadrien.chabran@sourcegraph.com>
This commit is contained in:
parent
cb41db37cb
commit
dc478c82dd
@ -1,4 +1,4 @@
|
||||
# Provides secrets like GH_TOKEN and PERCY_TOKEN via --action_env flag.
|
||||
# Provides secrets like GH_TOKEN via --action_env flag.
|
||||
# Generated via the `.buildkite/hooks/post-checkout` hook.
|
||||
try-import %workspace%/.aspect/bazelrc/ci.generated.bazelrc
|
||||
|
||||
@ -32,7 +32,7 @@ common --test_env=HEADLESS=false
|
||||
common --test_env=SOURCEGRAPH_BASE_URL="http://127.0.0.1:7080"
|
||||
common --test_env=DISPLAY=:99
|
||||
|
||||
# Provides git commit, branch information to build targets like Percy via status file.
|
||||
# Provides git commit, branch information to build targets via status file.
|
||||
# https://bazel.build/docs/user-manual#workspace-status
|
||||
common --workspace_status_command=./dev/bazel_buildkite_stamp_vars.sh
|
||||
|
||||
|
||||
@ -32,4 +32,4 @@ done
|
||||
ln -s "$(pwd)/dev/ci/scripts/annotated-command.sh" an 2>/dev/null || true
|
||||
|
||||
# Provides secrets to the client integration tests target.
|
||||
echo -e "build --action_env=GH_TOKEN=$GH_TOKEN\nbuild --action_env=PERCY_TOKEN=$PERCY_TOKEN" >.aspect/bazelrc/ci.generated.bazelrc
|
||||
echo -e "build --action_env=GH_TOKEN=$GH_TOKEN" >.aspect/bazelrc/ci.generated.bazelrc
|
||||
|
||||
27
.percy.yml
27
.percy.yml
@ -1,27 +0,0 @@
|
||||
version: 2
|
||||
snapshot:
|
||||
widths:
|
||||
- 1920 # Full-width browser window
|
||||
percy-css: |
|
||||
.percy-hide,
|
||||
.monaco-editor .cursor {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
.percy-inactive-element {
|
||||
pointer-events: none !important;
|
||||
}
|
||||
.percy-display-none {
|
||||
display: none !important;
|
||||
}
|
||||
discovery:
|
||||
disable-cache: true
|
||||
percy:
|
||||
# Defer uploading snapshots until the very end of the test suite.
|
||||
# This allows many snapshots with the same name AND different widths to be merged together.
|
||||
# This is useful for flaky client integration tests that can be retried automatically.
|
||||
#
|
||||
# This should prevent creating a Percy build if the test suite fails according to sources:
|
||||
# 1. The exit code is used force stop the local Percy server: https://github.com/percy/cli/blob/9c89383d6e1a9aa41f0c83f8e4b9ddcdf827583b/packages/cli-exec/src/exec.js#L78-L81
|
||||
# 2. The `force` options is propagated to `this.#snapshots.close(true)`: https://github.com/percy/cli/blob/master/packages/core/src/percy.js#L219-L223
|
||||
# 3. The snapshots queue is cleared if `force` is true: https://github.com/percy/cli/blob/9c89383d6e1a9aa41f0c83f8e4b9ddcdf827583b/packages/core/src/queue.js#L177
|
||||
defer-uploads: true
|
||||
@ -5,7 +5,7 @@ const { decompressRecordings, deleteRecordings } = require('./utils')
|
||||
// eslint-disable-next-line no-void
|
||||
void (async () => {
|
||||
await decompressRecordings()
|
||||
shelljs.exec('POLLYJS_MODE=replay pnpm percy exec --quiet -- pnpm run-integration', async code => {
|
||||
shelljs.exec('POLLYJS_MODE=replay pnpm run-integration', async code => {
|
||||
await deleteRecordings()
|
||||
process.exit(code)
|
||||
})
|
||||
|
||||
@ -285,8 +285,6 @@ describe('GitHub', () => {
|
||||
// },
|
||||
// })
|
||||
|
||||
// await percySnapshot(driver.page, 'Browser extension: GitHub - blob view with code intel popup')
|
||||
|
||||
// // 2. Check that token click does not do anything by default
|
||||
// await token.click()
|
||||
// await driver.page.waitForTimeout(1000)
|
||||
|
||||
@ -207,8 +207,5 @@ describe('GitLab', () => {
|
||||
timeout: 6000,
|
||||
},
|
||||
})
|
||||
|
||||
// disable flaky snapshot
|
||||
// await percySnapshot(driver.page, 'Browser extension: GitLab - blob view with code intel popup')
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import type puppeteer from 'puppeteer'
|
||||
|
||||
import { percySnapshot as percySnapshotCommon } from '@sourcegraph/shared/src/testing/driver'
|
||||
|
||||
/**
|
||||
* Find a tab that contains the browser extension's after-install page (url
|
||||
* ending in `/after_install.html`) and, if found, close it.
|
||||
@ -25,22 +23,3 @@ export async function closeInstallPageTab(browser: puppeteer.Browser): Promise<v
|
||||
tries++
|
||||
}
|
||||
}
|
||||
|
||||
const extractExtensionStyles = (page: puppeteer.Page): Promise<string> =>
|
||||
page.evaluate(() =>
|
||||
[...document.styleSheets]
|
||||
.filter(styleSheet => styleSheet.href?.startsWith('chrome-extension://'))
|
||||
.reduce(
|
||||
(styleSheetRules, styleSheet) =>
|
||||
styleSheetRules.concat(
|
||||
[...styleSheet.cssRules].reduce((rules, rule) => rules.concat(rule.cssText), '')
|
||||
),
|
||||
''
|
||||
)
|
||||
)
|
||||
|
||||
export const percySnapshot: typeof percySnapshotCommon = async (page, name, options) => {
|
||||
const extensionStyles = await extractExtensionStyles(page)
|
||||
|
||||
return percySnapshotCommon(page, name, { ...options, percyCSS: extensionStyles.concat(options?.percyCSS || '') })
|
||||
}
|
||||
|
||||
@ -53,19 +53,6 @@ ts_binary(
|
||||
visibility = ["//client:__subpackages__"],
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = "run_mocha_tests_with_percy",
|
||||
srcs = ["runMochaTestsWithPercy.js"],
|
||||
data = [
|
||||
"//:node_modules/@percy/cli",
|
||||
"//:node_modules/@percy/puppeteer",
|
||||
"//:node_modules/mocha",
|
||||
"//:node_modules/puppeteer",
|
||||
"//:node_modules/resolve-bin",
|
||||
],
|
||||
visibility = ["//client:__subpackages__"],
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = "mocha-reporter",
|
||||
srcs = [
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
const path = require('path')
|
||||
const { readFileSync } = require('fs')
|
||||
const { execFileSync } = require('child_process')
|
||||
|
||||
const puppeteer = require('puppeteer')
|
||||
const resolveBin = require('resolve-bin')
|
||||
|
||||
// Reads environment variables set by Bazel.
|
||||
// It also adds a custom environment variable, "PERCY_BROWSER_EXECUTABLE", which points
|
||||
// to the Puppeteer browser executable downloaded in the postinstall script.
|
||||
/** @returns {Record<string, string>} env vars */
|
||||
function getEnvVars() {
|
||||
// JS_BINARY__EXECROOT – Set by Bazel `js_test` rule.
|
||||
// JS_BINARY__BINDIR – Set by Bazel `js_test` rule.
|
||||
const { JS_BINARY__EXECROOT, JS_BINARY__BINDIR } = process.env
|
||||
|
||||
if (!JS_BINARY__EXECROOT || !JS_BINARY__BINDIR) {
|
||||
throw new Error('Missing required environment variables')
|
||||
}
|
||||
|
||||
// Read the Bazel status file and convert its contents to an object.
|
||||
// Here we provide information about the current BRANCH and COMMIT to allow Percy to
|
||||
// build the correct visual diff report and auto-accept change on `main` if we're on it.
|
||||
// https://github.com/percy/cli/blob/059ec21653a07105e223aa5a3ec1f815a7123ad7/packages/env/src/environment.js#L138-L139
|
||||
// https://bazel.build/docs/user-manual#workspace-status
|
||||
//
|
||||
// NB: we derive the volatile-status.txt file path from the JS_BINARY__BINDIR since we are
|
||||
// intentionally pulling volatile data without defining the volatile status as an input so we
|
||||
// don't bust the cache with its contents of volatile-status.txt
|
||||
// (https://github.com/bazelbuild/bazel/issues/16231). This can be improved in the future by using
|
||||
// the new --experimental_remote_cache_key_ignore_stamping flag in Bazel to filter out the
|
||||
// volatile-status.txt file from the action inputs
|
||||
// (https://github.com/bazelbuild/bazel/pull/16240)
|
||||
const statusFilePath = path.join(
|
||||
path.dirname(path.dirname(path.join(JS_BINARY__EXECROOT, JS_BINARY__BINDIR))),
|
||||
'volatile-status.txt'
|
||||
)
|
||||
const volatileEnvVariables = Object.fromEntries(
|
||||
readFileSync(statusFilePath, 'utf8')
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.map(item => item.split(' '))
|
||||
)
|
||||
|
||||
// Merge the custom "PERCY_BROWSER_EXECUTABLE" variable with the Bazel-provided variables
|
||||
// This is required to skip the "download Chromium" step in Percy's "exec" command.
|
||||
// https://docs.percy.io/docs/skipping-asset-discovery-browser-download#using-an-environment-variable
|
||||
const customEnvVariables = {
|
||||
...volatileEnvVariables,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
PERCY_BROWSER_EXECUTABLE: puppeteer.executablePath(),
|
||||
}
|
||||
|
||||
// Convert the merged environment variables to a string with the "KEY=VALUE" format
|
||||
return customEnvVariables
|
||||
}
|
||||
|
||||
// Resolve the binary paths for Percy and Mocha
|
||||
const percyBin = resolveBin.sync('@percy/cli', { executable: 'percy' })
|
||||
const mochaBin = resolveBin.sync('mocha')
|
||||
|
||||
// Extract command-line arguments to pass to Mocha
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
// Execute the final command, inheriting the stdio settings from the parent process and and wrapping
|
||||
// the Mocha command with Percy's "exec" command (https://docs.percy.io/docs/cli-exec).
|
||||
execFileSync(percyBin, ['exec', '--', mochaBin, ...args], {
|
||||
env: { ...process.env, ...getEnvVars() },
|
||||
stdio: 'inherit',
|
||||
})
|
||||
@ -60,7 +60,6 @@ ts_project(
|
||||
deps = [
|
||||
"//:node_modules/@apollo/client",
|
||||
"//:node_modules/@axe-core/puppeteer",
|
||||
"//:node_modules/@percy/puppeteer",
|
||||
"//:node_modules/@pollyjs/adapter",
|
||||
"//:node_modules/@pollyjs/core",
|
||||
"//:node_modules/@pollyjs/persister-fs",
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
|
||||
import realPercySnapshot from '@percy/puppeteer'
|
||||
import delay from 'delay'
|
||||
import expect from 'expect'
|
||||
import * as jsonc from 'jsonc-parser'
|
||||
import { escapeRegExp } from 'lodash'
|
||||
import { readFile } from 'mz/fs'
|
||||
import puppeteer, {
|
||||
type PageEventObject,
|
||||
type Page,
|
||||
type Serializable,
|
||||
type LaunchOptions,
|
||||
type ConsoleMessage,
|
||||
type Target,
|
||||
type BrowserLaunchArgumentOptions,
|
||||
type BrowserConnectOptions,
|
||||
type BrowserLaunchArgumentOptions,
|
||||
type ConsoleMessage,
|
||||
type LaunchOptions,
|
||||
type Page,
|
||||
type PageEventObject,
|
||||
type Serializable,
|
||||
type Target,
|
||||
} from 'puppeteer'
|
||||
import { from, fromEvent, merge, Subscription } from 'rxjs'
|
||||
import { filter, map, concatAll, mergeMap, mergeAll, takeUntil } from 'rxjs/operators'
|
||||
import { Subscription, from, fromEvent, merge } from 'rxjs'
|
||||
import { concatAll, filter, map, mergeAll, mergeMap, takeUntil } from 'rxjs/operators'
|
||||
import { Key } from 'ts-key-enum'
|
||||
|
||||
import { isDefined, logger } from '@sourcegraph/common'
|
||||
@ -37,7 +36,7 @@ import type { Settings } from '../settings/settings'
|
||||
|
||||
import { getConfig } from './config'
|
||||
import { formatPuppeteerConsoleMessage } from './console'
|
||||
import { readEnvironmentBoolean, retry } from './utils'
|
||||
import { retry } from './utils'
|
||||
|
||||
/**
|
||||
* Returns a Promise for the next emission of the given event on the given Puppeteer page.
|
||||
@ -56,28 +55,6 @@ export const extractStyles = (page: puppeteer.Page): Promise<string> =>
|
||||
)
|
||||
)
|
||||
|
||||
interface CommonSnapshotOptions {
|
||||
widths?: number[]
|
||||
minHeight?: number
|
||||
percyCSS?: string
|
||||
enableJavaScript?: boolean
|
||||
devicePixelRatio?: number
|
||||
scope?: string
|
||||
}
|
||||
|
||||
export const percySnapshot = async (
|
||||
page: puppeteer.Page,
|
||||
name: string,
|
||||
options: CommonSnapshotOptions = {}
|
||||
): Promise<void> => {
|
||||
if (!readEnvironmentBoolean({ variable: 'PERCY_ON', defaultValue: false })) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
const pageStyles = await extractStyles(page)
|
||||
return realPercySnapshot(page, name, { ...options, percyCSS: pageStyles.concat(options.percyCSS || '') })
|
||||
}
|
||||
|
||||
export const BROWSER_EXTENSION_DEV_ID = 'bmfbcejdknlknpncfpeloejonjoledha'
|
||||
|
||||
/**
|
||||
@ -723,7 +700,6 @@ export class Driver {
|
||||
/**
|
||||
* Finds the first HTML element matching the text using the regular expressions returned in
|
||||
* {@link findElementRegexpStrings}.
|
||||
*
|
||||
* @param options specifies additional parameters for finding the element. If you want to wait
|
||||
* until the element appears, specify the `wait` field (which can contain additional inner
|
||||
* options for how long to wait).
|
||||
|
||||
@ -40,7 +40,7 @@ export const RunServerSideModal: React.FunctionComponent<RunServerSideModalProps
|
||||
</Text>
|
||||
|
||||
<video
|
||||
className="w-100 h-auto shadow percy-hide"
|
||||
className="w-100 h-auto shadow"
|
||||
width={1280}
|
||||
height={720}
|
||||
autoPlay={true}
|
||||
|
||||
@ -125,7 +125,7 @@ export class MonacoBatchSpecEditor extends React.PureComponent<Props, State> {
|
||||
public render(): JSX.Element | null {
|
||||
return (
|
||||
<MonacoEditor
|
||||
className={classNames('percy-hide chromatic-ignore', styles.editor, this.props.className)}
|
||||
className={classNames('chromatic-ignore', styles.editor, this.props.className)}
|
||||
language="yaml"
|
||||
height="auto"
|
||||
isLightTheme={this.props.isLightTheme}
|
||||
|
||||
@ -103,7 +103,7 @@ const MemoizedExecutionWorkspaces: React.FunctionComponent<React.PropsWithChildr
|
||||
<>
|
||||
<div className={styles.videoContainer}>
|
||||
<video
|
||||
className="w-100 percy-hide"
|
||||
className="w-100"
|
||||
autoPlay={true}
|
||||
muted={true}
|
||||
loop={true}
|
||||
|
||||
@ -39,7 +39,7 @@ export const GettingStarted: React.FunctionComponent<React.PropsWithChildren<Get
|
||||
<div className="row align-items-center">
|
||||
<div className="col-12 col-md-7">
|
||||
<video
|
||||
className="w-100 h-auto shadow percy-hide"
|
||||
className="w-100 h-auto shadow"
|
||||
width={1280}
|
||||
height={720}
|
||||
autoPlay={allowAutoplay}
|
||||
|
||||
@ -118,7 +118,6 @@ mocha_test(
|
||||
"WEB_BUNDLE_PATH": "$(rootpath //client/web:app)",
|
||||
},
|
||||
flaky = True,
|
||||
is_percy_enabled = True,
|
||||
tags = [
|
||||
"no-sandbox",
|
||||
"requires-network",
|
||||
|
||||
@ -15,19 +15,19 @@ import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testin
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import {
|
||||
BatchChangeState,
|
||||
BatchSpecState,
|
||||
ChangesetCheckState,
|
||||
ChangesetReviewState,
|
||||
ChangesetSpecType,
|
||||
DiffHunkLineType,
|
||||
type BatchChangeBatchSpecsResult,
|
||||
type BatchChangeBatchSpecsVariables,
|
||||
type BatchChangeByNamespaceResult,
|
||||
type BatchChangeChangesetsResult,
|
||||
type BatchChangeChangesetsVariables,
|
||||
BatchChangeState,
|
||||
BatchSpecState,
|
||||
ChangesetCheckState,
|
||||
type ChangesetCountsOverTimeResult,
|
||||
type ChangesetCountsOverTimeVariables,
|
||||
ChangesetReviewState,
|
||||
ChangesetSpecType,
|
||||
DiffHunkLineType,
|
||||
type ExternalChangesetFileDiffsFields,
|
||||
type ExternalChangesetFileDiffsResult,
|
||||
type ExternalChangesetFileDiffsVariables,
|
||||
@ -37,7 +37,6 @@ import {
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { percySnapshotWithVariants } from './utils'
|
||||
|
||||
const now = new Date()
|
||||
|
||||
@ -551,7 +550,6 @@ describe('Batches', () => {
|
||||
await driver.page.waitForSelector('.test-batches-list-page')
|
||||
await driver.page.click('[data-testid="test-getting-started-btn"]')
|
||||
await driver.page.waitForSelector('[data-testid="test-getting-started"]')
|
||||
await percySnapshotWithVariants(driver.page, 'Batch changes getting started page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -578,7 +576,6 @@ describe('Batches', () => {
|
||||
driver.sourcegraphBaseUrl + '/users/alice/batch-changes/test-batch-change'
|
||||
)
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Batch Changes List')
|
||||
// TODO: Disabled, we need to audit SSBC things on this list before it can pass.
|
||||
// await accessibilityAudit(driver.page)
|
||||
})
|
||||
@ -626,7 +623,6 @@ describe('Batches', () => {
|
||||
it.skip('is styled correctly', async () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/batch-changes/create')
|
||||
await driver.page.waitForSelector('[data-testid="batch-spec-yaml-file"]')
|
||||
await percySnapshotWithVariants(driver.page, 'Create batch change')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -655,7 +651,6 @@ describe('Batches', () => {
|
||||
})
|
||||
// View overview page.
|
||||
await driver.page.waitForSelector('.test-batch-change-details-page', { visible: true })
|
||||
await percySnapshotWithVariants(driver.page, `Batch change details page ${entityType}`)
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
// we wait for the changesets to be loaded in the browser before proceeding
|
||||
@ -915,7 +910,6 @@ describe('Batches', () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + namespaceURL + '/batch-changes/apply/spec123')
|
||||
// View overview page.
|
||||
await driver.page.waitForSelector('.test-batch-change-apply-page')
|
||||
await percySnapshotWithVariants(driver.page, `Batch change preview page ${entityType}`)
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
// Expand one changeset.
|
||||
@ -1047,7 +1041,6 @@ describe('Batches', () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/users/alice/settings/batch-changes')
|
||||
// View settings page.
|
||||
await driver.page.waitForSelector('.test-batches-settings-page')
|
||||
await percySnapshotWithVariants(driver.page, 'User batch changes settings page')
|
||||
await accessibilityAudit(driver.page)
|
||||
// Wait for list to load.
|
||||
await driver.page.waitForSelector('.test-code-host-connection-node')
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import assert from 'assert'
|
||||
|
||||
import expect from 'expect'
|
||||
import { describe, afterEach, before, beforeEach, after } from 'mocha'
|
||||
import { after, afterEach, before, beforeEach, describe } from 'mocha'
|
||||
|
||||
import { mixedSearchStreamEvents } from '@sourcegraph/shared/src/search/integration/streaming-search-mocks'
|
||||
import { accessibilityAudit } from '@sourcegraph/shared/src/testing/accessibility'
|
||||
import { type Driver, createDriverForTest } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import { type WebIntegrationTestContext, createWebIntegrationTestContext } from './context'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { siteID, siteGQLID } from './jscontext'
|
||||
import { createEditorAPI, isElementDisabled, percySnapshotWithVariants } from './utils'
|
||||
import { siteGQLID, siteID } from './jscontext'
|
||||
import { createEditorAPI, isElementDisabled } from './utils'
|
||||
|
||||
describe('Code monitoring', () => {
|
||||
let driver: Driver
|
||||
@ -112,7 +112,6 @@ describe('Code monitoring', () => {
|
||||
it('is styled correctly', async () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/code-monitoring')
|
||||
await driver.page.waitForSelector('[data-testid="code-monitoring-page"]')
|
||||
await percySnapshotWithVariants(driver.page, 'Code monitor list')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -122,8 +121,6 @@ describe('Code monitoring', () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/code-monitoring/new')
|
||||
await driver.page.waitForSelector('[data-testid="name-input"]')
|
||||
|
||||
// Screenshot test disabled: https://github.com/sourcegraph/sourcegraph/issues/41743
|
||||
// await percySnapshotWithVariants(driver.page, 'Code monitoring - Form')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
await driver.page.type('[data-testid="name-input"]', 'test monitor')
|
||||
|
||||
@ -3,20 +3,20 @@ import assert from 'assert'
|
||||
import { afterEach, beforeEach, describe, it } from 'mocha'
|
||||
import type { ElementHandle, MouseButton } from 'puppeteer'
|
||||
|
||||
import { type JsonDocument, SyntaxKind } from '@sourcegraph/shared/src/codeintel/scip'
|
||||
import { SyntaxKind, type JsonDocument } from '@sourcegraph/shared/src/codeintel/scip'
|
||||
import type { SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { type Driver, createDriverForTest, percySnapshot } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import type { WebGraphQlOperations } from '../graphql-operations'
|
||||
|
||||
import { type WebIntegrationTestContext, createWebIntegrationTestContext } from './context'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import {
|
||||
createResolveRepoRevisionResult,
|
||||
createFileExternalLinksResult,
|
||||
createTreeEntriesResult,
|
||||
createBlobContentResult,
|
||||
createFileExternalLinksResult,
|
||||
createFileTreeEntriesResult,
|
||||
createResolveRepoRevisionResult,
|
||||
createTreeEntriesResult,
|
||||
} from './graphQlResponseHelpers'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { createEditorAPI, type EditorAPI } from './utils'
|
||||
@ -125,7 +125,6 @@ describe('CodeMirror blob view', () => {
|
||||
)
|
||||
await waitForView()
|
||||
await driver.page.waitForSelector('.test-breadcrumb')
|
||||
await percySnapshot(driver.page, 'truncates long file paths properly')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -16,7 +16,6 @@ import type { WebGraphQlOperations } from '../graphql-operations'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { createCodyContextFiltersResult } from './graphQlResponseHelpers'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { percySnapshotWithVariants } from './utils'
|
||||
|
||||
describe('RepositoryCommitPage', () => {
|
||||
const repositoryName = 'github.com/sourcegraph/sourcegraph'
|
||||
@ -329,8 +328,6 @@ describe('RepositoryCommitPage', () => {
|
||||
it('Display diff in unified mode', async () => {
|
||||
await driver.page.goto(`${driver.sourcegraphBaseUrl}/${repositoryName}/-/commit/${commitID}`)
|
||||
await driver.page.waitForSelector('.test-file-diff-node', { visible: true })
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Commit page - Unified mode')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -342,8 +339,6 @@ describe('RepositoryCommitPage', () => {
|
||||
await driver.page.evaluate(element => element.click(), splitRadioButton)
|
||||
|
||||
await driver.page.waitForSelector('[data-split-mode="split"]', { visible: true })
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Commit page - Split mode')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -9,9 +9,9 @@ import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing
|
||||
|
||||
import { TimeIntervalStepUnit } from '../../graphql-operations'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from '../context'
|
||||
import { createEditorAPI, percySnapshotWithVariants } from '../utils'
|
||||
import { createEditorAPI } from '../utils'
|
||||
|
||||
import { SEARCH_INSIGHT_LIVE_PREVIEW_FIXTURE, LANG_STATS_INSIGHT_DATA_FIXTURE } from './fixtures/runtime-insights'
|
||||
import { LANG_STATS_INSIGHT_DATA_FIXTURE, SEARCH_INSIGHT_LIVE_PREVIEW_FIXTURE } from './fixtures/runtime-insights'
|
||||
import { overrideInsightsGraphQLApi } from './utils/override-insights-graphql-api'
|
||||
|
||||
describe('Code insight create insight page', () => {
|
||||
@ -41,8 +41,6 @@ describe('Code insight create insight page', () => {
|
||||
// Waiting for all important part page be rendered.
|
||||
await driver.page.waitForSelector('[data-testid="create-search-insights"]')
|
||||
await driver.page.waitForSelector('[data-testid="create-lang-usage-insight"]')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Create new insight page — Welcome popup')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -53,8 +51,6 @@ describe('Code insight create insight page', () => {
|
||||
// Waiting for all important part page be rendered.
|
||||
await driver.page.waitForSelector('[data-testid="create-search-insights"]')
|
||||
await driver.page.waitForSelector('[data-testid="create-lang-usage-insight"]')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Create new insight page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -107,8 +103,6 @@ describe('Code insight create insight page', () => {
|
||||
await driver.page.click('input[name="title"]')
|
||||
// Change insight title
|
||||
await driver.page.type('input[name="title"]', 'Test insight title')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Code insights create new language usage insight')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
const addToUserConfigRequest = await testContext.waitForGraphQLRequest(async () => {
|
||||
|
||||
@ -9,7 +9,7 @@ import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testin
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from '../context'
|
||||
import { createEditorAPI, percySnapshotWithVariants } from '../utils'
|
||||
import { createEditorAPI } from '../utils'
|
||||
|
||||
import { createJITMigrationToGQLInsightMetadataFixture } from './fixtures/insights-metadata'
|
||||
import { SEARCH_INSIGHT_LIVE_PREVIEW_FIXTURE } from './fixtures/runtime-insights'
|
||||
@ -295,8 +295,6 @@ describe('Code insight edit insight page', () => {
|
||||
await driver.page.waitForSelector(
|
||||
'[data-testid="line-chart__content"] [data-line-name="Imports of new graphql-operations types"] circle'
|
||||
)
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Code insights edit page with search-based insight creation UI')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
// Gather all filled inputs within a creation UI form.
|
||||
|
||||
@ -7,7 +7,6 @@ import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testin
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from '../context'
|
||||
import { percySnapshotWithVariants } from '../utils'
|
||||
|
||||
import { MIGRATION_TO_GQL_INSIGHT_DATA_FIXTURE } from './fixtures/calculated-insights'
|
||||
import { createJITMigrationToGQLInsightMetadataFixture } from './fixtures/insights-metadata'
|
||||
@ -36,7 +35,6 @@ describe('Code insights single insight page', () => {
|
||||
async function takeChartSnapshot(name: string): Promise<void> {
|
||||
await driver.page.waitForSelector('svg circle')
|
||||
await delay(500)
|
||||
await percySnapshotWithVariants(driver.page, name)
|
||||
}
|
||||
|
||||
it('is styled correctly with common backend insights', async () => {
|
||||
|
||||
@ -12,23 +12,22 @@ import {
|
||||
} from '@sourcegraph/shared/src/search/integration/streaming-search-mocks'
|
||||
import type { SearchEvent } from '@sourcegraph/shared/src/search/stream'
|
||||
import { accessibilityAudit } from '@sourcegraph/shared/src/testing/accessibility'
|
||||
import { type Driver, createDriverForTest } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import {
|
||||
NotebookBlockType,
|
||||
SymbolKind,
|
||||
type CreateNotebookBlockInput,
|
||||
type NotebookFields,
|
||||
type WebGraphQlOperations,
|
||||
NotebookBlockType,
|
||||
SymbolKind,
|
||||
} from '../graphql-operations'
|
||||
import type { BlockType } from '../notebooks'
|
||||
|
||||
import { type WebIntegrationTestContext, createWebIntegrationTestContext } from './context'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { createResolveRepoRevisionResult } from './graphQlResponseHelpers'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { siteGQLID, siteID } from './jscontext'
|
||||
import { percySnapshotWithVariants } from './utils'
|
||||
|
||||
const viewerSettings: Partial<WebGraphQlOperations & SharedGraphQlOperations> = {
|
||||
ViewerSettings: () => ({
|
||||
@ -269,7 +268,6 @@ describe('Search Notebook', () => {
|
||||
await driver.page.waitForSelector('[data-block-id]', { visible: true })
|
||||
const blockIds = await getBlockIds()
|
||||
expect(blockIds).toHaveLength(2)
|
||||
await percySnapshotWithVariants(driver.page, 'Search notebook')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -341,7 +339,6 @@ describe('Search Notebook', () => {
|
||||
queryResultContainerSelector
|
||||
)
|
||||
expect(isResultContainerVisible).toBeTruthy()
|
||||
await percySnapshotWithVariants(driver.page, 'Search notebook with markdown and query blocks')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -782,7 +779,6 @@ ${process.env.SOURCEGRAPH_BASE_URL}/github.com/sourcegraph/sourcegraph@branch/-/
|
||||
it('Notebooks list page should be accessible', async () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/notebooks?tab=notebooks')
|
||||
await driver.page.waitForSelector('[data-testid="filtered-connection-nodes"]', { visible: true })
|
||||
await percySnapshotWithVariants(driver.page, 'Notebooks list')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -5,16 +5,16 @@ import { afterEach, beforeEach, describe, it } from 'mocha'
|
||||
import { subtypeOf } from '@sourcegraph/common'
|
||||
import type { SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { accessibilityAudit } from '@sourcegraph/shared/src/testing/accessibility'
|
||||
import { type Driver, createDriverForTest } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { emptyResponse } from '@sourcegraph/shared/src/testing/integration/graphQlResults'
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
import { retry } from '@sourcegraph/shared/src/testing/utils'
|
||||
|
||||
import type { WebGraphQlOperations, OrganizationResult } from '../graphql-operations'
|
||||
import type { OrganizationResult, WebGraphQlOperations } from '../graphql-operations'
|
||||
|
||||
import { type WebIntegrationTestContext, createWebIntegrationTestContext } from './context'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { createEditorAPI, percySnapshotWithVariants } from './utils'
|
||||
import { createEditorAPI } from './utils'
|
||||
|
||||
describe('Organizations', () => {
|
||||
const testOrg = subtypeOf<OrganizationResult['organization']>()({
|
||||
@ -95,8 +95,6 @@ describe('Organizations', () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/site-admin/organizations')
|
||||
|
||||
await driver.page.waitForSelector('.test-create-org-button')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Site admin org page')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
await driver.page.click('.test-create-org-button')
|
||||
@ -169,7 +167,6 @@ describe('Organizations', () => {
|
||||
const editor = await createEditorAPI(driver, '.test-settings-file .test-editor')
|
||||
|
||||
// Take snapshot before updating text in the editor to avoid flakiness.
|
||||
await percySnapshotWithVariants(driver.page, 'Organization settings page')
|
||||
await editor.replace(updatedSettings, 'paste')
|
||||
|
||||
const variables = await testContext.waitForGraphQLRequest(async () => {
|
||||
@ -241,8 +238,6 @@ describe('Organizations', () => {
|
||||
2,
|
||||
'Expected members list to show 2 members.'
|
||||
)
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Organization members list')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
// Override for the fetch post-removal
|
||||
|
||||
@ -12,7 +12,6 @@ import type { UserSettingsAreaUserFields } from '../graphql-operations'
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { percySnapshotWithVariants } from './utils'
|
||||
|
||||
const now = new Date()
|
||||
|
||||
@ -67,7 +66,6 @@ describe('User profile page', () => {
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/users/test/settings/profile')
|
||||
await driver.page.waitForSelector('[data-testid="user-profile-form-fields"]')
|
||||
await percySnapshotWithVariants(driver.page, 'User Profile Settings Page')
|
||||
await accessibilityAudit(driver.page)
|
||||
await driver.replaceText({
|
||||
selector: '[data-testid="test-UserProfileFormFields__displayName"]',
|
||||
@ -126,7 +124,6 @@ describe('User Different Settings Page', () => {
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/users/test/settings/emails')
|
||||
await driver.page.waitForSelector('[data-testid="user-settings-emails-page"]')
|
||||
await percySnapshotWithVariants(driver.page, 'User Email Settings Page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -187,7 +184,6 @@ describe('User Different Settings Page', () => {
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/user/settings/security')
|
||||
await driver.page.waitForSelector('.user-settings-account-security-page')
|
||||
await percySnapshotWithVariants(driver.page, 'User Account Security Settings Page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -16,25 +16,25 @@ import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing
|
||||
|
||||
import {
|
||||
DiffHunkLineType,
|
||||
ExternalServiceKind,
|
||||
type RepositoryContributorsResult,
|
||||
type WebGraphQlOperations,
|
||||
ExternalServiceKind,
|
||||
} from '../graphql-operations'
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import {
|
||||
createResolveRepoRevisionResult,
|
||||
createFileExternalLinksResult,
|
||||
createTreeEntriesResult,
|
||||
createBlobContentResult,
|
||||
createRepoChangesetsStatsResult,
|
||||
createFileNamesResult,
|
||||
createResolveCloningRepoRevisionResult,
|
||||
createFileTreeEntriesResult,
|
||||
createCodyContextFiltersResult,
|
||||
createFileExternalLinksResult,
|
||||
createFileNamesResult,
|
||||
createFileTreeEntriesResult,
|
||||
createRepoChangesetsStatsResult,
|
||||
createResolveCloningRepoRevisionResult,
|
||||
createResolveRepoRevisionResult,
|
||||
createTreeEntriesResult,
|
||||
} from './graphQlResponseHelpers'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { createEditorAPI, percySnapshotWithVariants, removeContextFromQuery } from './utils'
|
||||
import { createEditorAPI, removeContextFromQuery } from './utils'
|
||||
|
||||
const getCommonRepositoryGraphQlResults = (
|
||||
repositoryName: string,
|
||||
@ -288,8 +288,6 @@ describe('Repository', () => {
|
||||
// Assert that the directory listing displays properly
|
||||
await driver.page.waitForSelector('.test-tree-entries')
|
||||
|
||||
// TODO: Reenable later, percy is erroring out on remote images not loading.
|
||||
// await percySnapshotWithVariants(driver.page, 'Repository index page')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
const numberOfFileEntries = await driver.page.evaluate(
|
||||
@ -488,12 +486,10 @@ describe('Repository', () => {
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + repositorySourcegraphUrl)
|
||||
|
||||
// Wait for clone in progress message before Percy snapshot.
|
||||
// Wait for clone in progress message.
|
||||
await driver.page.waitForSelector('[data-testid="hero-page-subtitle"]')
|
||||
// Verify that we show the respective message in the UI.
|
||||
await assertSelectorHasText('[data-testid="hero-page-subtitle"]', 'Cloning in progress')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Repository cloning in progress page')
|
||||
})
|
||||
|
||||
it('works with spaces in the repository name', async () => {
|
||||
@ -740,7 +736,6 @@ describe('Repository', () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/github.com/sourcegraph/sourcegraph/-/commits')
|
||||
await driver.page.waitForSelector('[data-testid="commits-page"]', { visible: true })
|
||||
await driver.page.waitForSelector('.list-group-item', { visible: true })
|
||||
await percySnapshotWithVariants(driver.page, 'Repository commits page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -852,7 +847,6 @@ describe('Repository', () => {
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + repositorySourcegraphUrl)
|
||||
await driver.page.waitForSelector('.test-filtered-contributors-connection')
|
||||
await percySnapshotWithVariants(driver.page, 'Contributor list')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -1005,7 +999,6 @@ describe('Repository', () => {
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + repositorySourcegraphUrl)
|
||||
await driver.page.waitForSelector('[data-testid="active-branches-list"]')
|
||||
await percySnapshotWithVariants(driver.page, 'Repository branches page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -1109,7 +1102,6 @@ describe('Repository', () => {
|
||||
await driver.page.waitForSelector('.test-filtered-tags-connection')
|
||||
await driver.page.click('input[name="query"]')
|
||||
await driver.page.waitForSelector('input[name="query"].focus-visible')
|
||||
await percySnapshotWithVariants(driver.page, 'Repository tags page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -1256,7 +1248,6 @@ describe('Repository', () => {
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + repositorySourcegraphUrl)
|
||||
await driver.page.waitForSelector('.test-file-diff-connection')
|
||||
await percySnapshotWithVariants(driver.page, 'Repository compare page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,7 +6,6 @@ import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { percySnapshotWithVariants } from './utils'
|
||||
|
||||
describe('RequestAccess', () => {
|
||||
let driver: Driver
|
||||
@ -43,8 +42,6 @@ describe('RequestAccess', () => {
|
||||
await driver.page.waitForSelector('#name')
|
||||
await driver.page.waitForSelector('#email')
|
||||
await driver.page.waitForSelector('#additionalInfo')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Request access page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -66,8 +63,6 @@ describe('RequestAccess', () => {
|
||||
window.history.replaceState({}, '', '/request-access/done')
|
||||
})
|
||||
await driver.page.waitForSelector('[data-testid="request-access-post-submit"]')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Request access page post-submit')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -3,20 +3,20 @@ import expect from 'expect'
|
||||
import { range } from 'lodash'
|
||||
import { afterEach, beforeEach, describe, test } from 'mocha'
|
||||
|
||||
import type { SharedGraphQlOperations, SearchContextMinimalFields } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import type { SearchContextMinimalFields, SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import {
|
||||
highlightFileResult,
|
||||
mixedSearchStreamEvents,
|
||||
} from '@sourcegraph/shared/src/search/integration/streaming-search-mocks'
|
||||
import { accessibilityAudit } from '@sourcegraph/shared/src/testing/accessibility'
|
||||
import { type Driver, createDriverForTest } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import type { WebGraphQlOperations } from '../graphql-operations'
|
||||
|
||||
import { type WebIntegrationTestContext, createWebIntegrationTestContext } from './context'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults, createViewerSettingsGraphQLOverride } from './graphQlResults'
|
||||
import { createEditorAPI, getSearchQueryInputConfig, percySnapshotWithVariants } from './utils'
|
||||
import { createEditorAPI, getSearchQueryInputConfig } from './utils'
|
||||
|
||||
const commonSearchGraphQLResults: Partial<WebGraphQlOperations & SharedGraphQlOperations> = {
|
||||
...commonWebGraphQlResults,
|
||||
@ -219,7 +219,6 @@ describe('Search contexts', () => {
|
||||
)
|
||||
|
||||
// Take Snapshot
|
||||
await percySnapshotWithVariants(driver.page, 'Create static search context page')
|
||||
await accessibilityAudit(driver.page)
|
||||
// Click create
|
||||
await driver.page.click('[data-testid="search-context-submit-button"]')
|
||||
@ -286,7 +285,6 @@ describe('Search contexts', () => {
|
||||
await editor.focus()
|
||||
|
||||
// Take Snapshot
|
||||
await percySnapshotWithVariants(driver.page, 'Create dynamic query search context page')
|
||||
|
||||
// Enter search query
|
||||
await editor.replace('repo:abc')
|
||||
@ -573,8 +571,6 @@ describe('Search contexts', () => {
|
||||
{},
|
||||
searchContextsCount
|
||||
)
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Search contexts list page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
|
||||
@ -2,32 +2,27 @@ import expect from 'expect'
|
||||
import { afterEach, beforeEach, describe, test } from 'mocha'
|
||||
import { Key } from 'ts-key-enum'
|
||||
|
||||
import { type SharedGraphQlOperations, SymbolKind } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { SymbolKind, type SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import {
|
||||
commitHighlightResult,
|
||||
commitSearchStreamEvents,
|
||||
diffSearchStreamEvents,
|
||||
diffHighlightResult,
|
||||
mixedSearchStreamEvents,
|
||||
diffSearchStreamEvents,
|
||||
highlightFileResult,
|
||||
symbolSearchStreamEvents,
|
||||
mixedSearchStreamEvents,
|
||||
ownerSearchStreamEvents,
|
||||
symbolSearchStreamEvents,
|
||||
} from '@sourcegraph/shared/src/search/integration/streaming-search-mocks'
|
||||
import type { SearchEvent } from '@sourcegraph/shared/src/search/stream'
|
||||
import { accessibilityAudit } from '@sourcegraph/shared/src/testing/accessibility'
|
||||
import { type Driver, createDriverForTest } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { createDriverForTest, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing/screenshotReporter'
|
||||
|
||||
import type { WebGraphQlOperations } from '../graphql-operations'
|
||||
|
||||
import { type WebIntegrationTestContext, createWebIntegrationTestContext } from './context'
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults, createViewerSettingsGraphQLOverride } from './graphQlResults'
|
||||
import {
|
||||
getSearchQueryInputConfig,
|
||||
percySnapshotWithVariants,
|
||||
type SearchQueryInput,
|
||||
withSearchQueryInput,
|
||||
} from './utils'
|
||||
import { getSearchQueryInputConfig, withSearchQueryInput, type SearchQueryInput } from './utils'
|
||||
|
||||
const mockDefaultStreamEvents: SearchEvent[] = [
|
||||
{
|
||||
@ -214,7 +209,6 @@ describe('Search', () => {
|
||||
await editor.replace('-file')
|
||||
await editor.selectSuggestion('-file')
|
||||
expect(await editor.getValue()).toStrictEqual('-file:')
|
||||
await percySnapshotWithVariants(driver.page, `Search home page (${name})`)
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -537,9 +531,6 @@ describe('Search', () => {
|
||||
await driver.page.waitForSelector('[data-testid="search-result-match-code-excerpt"] .match-highlight', {
|
||||
visible: true,
|
||||
})
|
||||
await percySnapshotWithVariants(driver.page, 'Streaming diff search syntax highlighting', {
|
||||
waitForCodeHighlighting: true,
|
||||
})
|
||||
|
||||
// Since current Chrome version that we use for integration tests
|
||||
// doesn't support @layers rule cody styles leak to the main scope and override
|
||||
@ -562,9 +553,6 @@ describe('Search', () => {
|
||||
visible: true,
|
||||
})
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Streaming commit search syntax highlighting', {
|
||||
waitForCodeHighlighting: true,
|
||||
})
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -580,13 +568,6 @@ describe('Search', () => {
|
||||
visible: true,
|
||||
})
|
||||
|
||||
await percySnapshotWithVariants(
|
||||
driver.page,
|
||||
'Streaming commit code, file and repo results with filter suggestions',
|
||||
{
|
||||
waitForCodeHighlighting: true,
|
||||
}
|
||||
)
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -602,9 +583,6 @@ describe('Search', () => {
|
||||
visible: true,
|
||||
})
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Streaming search symbols', {
|
||||
waitForCodeHighlighting: true,
|
||||
})
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
@ -620,9 +598,6 @@ describe('Search', () => {
|
||||
visible: true,
|
||||
})
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Streaming search owners', {
|
||||
waitForCodeHighlighting: true,
|
||||
})
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
@ -658,14 +633,12 @@ describe('Search', () => {
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/users/test/searches')
|
||||
await driver.page.waitForSelector('[data-testid="saved-searches-list-page"]')
|
||||
await percySnapshotWithVariants(driver.page, 'Saved searches list')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
|
||||
test('is styled correctly, with saved search form', async () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/users/test/searches/add')
|
||||
await driver.page.waitForSelector('[data-testid="saved-search-form"]')
|
||||
await percySnapshotWithVariants(driver.page, 'Saved search - Form')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -10,7 +10,7 @@ import { retry } from '@sourcegraph/shared/src/testing/utils'
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { createEditorAPI, isElementDisabled, percySnapshotWithVariants } from './utils'
|
||||
import { createEditorAPI, isElementDisabled } from './utils'
|
||||
|
||||
describe('Settings', () => {
|
||||
let driver: Driver
|
||||
@ -120,8 +120,6 @@ describe('Settings', () => {
|
||||
// The editor API needs to be created before taking the screenshot
|
||||
// (waits for the editor to be ready)
|
||||
const editor = await createEditorAPI(driver, '.test-settings-file .test-editor')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Settings page')
|
||||
await accessibilityAudit(driver.page)
|
||||
|
||||
// Replace with new settings
|
||||
|
||||
@ -6,7 +6,6 @@ import { afterEachSaveScreenshotIfFailed } from '@sourcegraph/shared/src/testing
|
||||
|
||||
import { createWebIntegrationTestContext, type WebIntegrationTestContext } from './context'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { percySnapshotWithVariants } from './utils'
|
||||
|
||||
describe('SignIn', () => {
|
||||
let driver: Driver
|
||||
@ -39,8 +38,6 @@ describe('SignIn', () => {
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/sign-in')
|
||||
await driver.page.waitForSelector('#username-or-email')
|
||||
await driver.page.waitForSelector('input[name="password"]')
|
||||
|
||||
await percySnapshotWithVariants(driver.page, 'Sign in page')
|
||||
await accessibilityAudit(driver.page)
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,8 +4,7 @@ import type { Page } from 'puppeteer'
|
||||
|
||||
import type { SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
|
||||
import { percySnapshot, type Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
import { readEnvironmentBoolean } from '@sourcegraph/shared/src/testing/utils'
|
||||
import type { Driver } from '@sourcegraph/shared/src/testing/driver'
|
||||
|
||||
import type { WebGraphQlOperations } from '../graphql-operations'
|
||||
|
||||
@ -41,17 +40,11 @@ const waitForCodeHighlighting = async (page: Page): Promise<void> => {
|
||||
|
||||
type ColorScheme = 'dark' | 'light'
|
||||
|
||||
/**
|
||||
* Percy couldn't capture <img /> since they have `src` values with testing domain name.
|
||||
* We need to call this function before asking Percy to take snapshots,
|
||||
* <img /> with base64 data would be visible on Percy snapshot
|
||||
*/
|
||||
export const convertImgSourceHttpToBase64 = async (page: Page): Promise<void> => {
|
||||
await page.evaluate(() => {
|
||||
// Skip images with data-skip-percy
|
||||
// Skip images with .cm-widgetBuffer, which CodeMirror uses when using a widget decoration
|
||||
// See https://github.com/sourcegraph/sourcegraph/issues/28949
|
||||
const imgs = document.querySelectorAll<HTMLImageElement>('img:not([data-skip-percy]):not(.cm-widgetBuffer)')
|
||||
const imgs = document.querySelectorAll<HTMLImageElement>('img:not(.cm-widgetBuffer)')
|
||||
|
||||
for (const img of imgs) {
|
||||
if (img.src.startsWith('data:image')) {
|
||||
@ -93,49 +86,6 @@ export const setColorScheme = async (
|
||||
])
|
||||
}
|
||||
|
||||
export interface PercySnapshotConfig {
|
||||
/**
|
||||
* How long to wait for the UI to settle before taking a screenshot.
|
||||
*/
|
||||
timeout: number
|
||||
waitForCodeHighlighting: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a Percy snapshot in 2 variants: dark/light
|
||||
*/
|
||||
export const percySnapshotWithVariants = async (
|
||||
page: Page,
|
||||
name: string,
|
||||
{ timeout = 1000, waitForCodeHighlighting = false } = {}
|
||||
): Promise<void> => {
|
||||
const percyEnabled = readEnvironmentBoolean({ variable: 'PERCY_ON', defaultValue: false })
|
||||
|
||||
if (!percyEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
// Theme-dark
|
||||
await setColorScheme(page, 'dark', waitForCodeHighlighting)
|
||||
// Wait for the theme class set by `useLayoutEffect` in `client/web/src/LegacyLayout.tsx`
|
||||
await page.waitForSelector('html.theme.theme-dark')
|
||||
// Wait for the UI to settle before converting images and taking the
|
||||
// screenshot.
|
||||
await page.waitForTimeout(timeout)
|
||||
await convertImgSourceHttpToBase64(page)
|
||||
await percySnapshot(page, `${name} - dark theme`)
|
||||
|
||||
// Theme-light
|
||||
await setColorScheme(page, 'light', waitForCodeHighlighting)
|
||||
// Wait for the theme class set by `useLayoutEffect` in `client/web/src/LegacyLayout.tsx`
|
||||
await page.waitForSelector('html.theme.theme-light')
|
||||
// Wait for the UI to settle before converting images and taking the
|
||||
// screenshot.
|
||||
await page.waitForTimeout(timeout)
|
||||
await convertImgSourceHttpToBase64(page)
|
||||
await percySnapshot(page, `${name} - light theme`)
|
||||
}
|
||||
|
||||
type Editor = 'monaco' | 'codemirror6' | 'v2'
|
||||
|
||||
export interface EditorAPI {
|
||||
|
||||
@ -376,7 +376,7 @@ export const StatusMessagesNavItem: React.FunctionComponent<React.PropsWithChild
|
||||
return (
|
||||
<Popover isOpen={isOpen} onOpenChange={event => setIsOpen(event.isOpen)}>
|
||||
<PopoverTrigger
|
||||
className="nav-link py-0 px-0 percy-hide chromatic-ignore"
|
||||
className="nav-link py-0 px-0 chromatic-ignore"
|
||||
as={Button}
|
||||
variant="link"
|
||||
aria-label={isOpen ? 'Hide status messages' : 'Show status messages'}
|
||||
|
||||
@ -5,7 +5,7 @@ exports[`StatusMessagesNavItem > all messages 1`] = `
|
||||
<button
|
||||
aria-expanded="false"
|
||||
aria-label="Show status messages"
|
||||
class="btn btnLink nav-link py-0 px-0 percy-hide chromatic-ignore"
|
||||
class="btn btnLink nav-link py-0 px-0 chromatic-ignore"
|
||||
type="button"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
@ -16,7 +16,7 @@ exports[`StatusMessagesNavItem > no messages 1`] = `
|
||||
<button
|
||||
aria-expanded="false"
|
||||
aria-label="Show status messages"
|
||||
class="btn btnLink nav-link py-0 px-0 percy-hide chromatic-ignore"
|
||||
class="btn btnLink nav-link py-0 px-0 chromatic-ignore"
|
||||
type="button"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
|
||||
@ -76,7 +76,7 @@ export const NotebooksGettingStartedTab: React.FunctionComponent<
|
||||
<div className="col-12 col-md-6">
|
||||
<video
|
||||
key={`notebooks_overview_video_${isLightTheme}`}
|
||||
className="w-100 h-auto shadow percy-hide"
|
||||
className="w-100 h-auto shadow"
|
||||
muted={true}
|
||||
playsInline={true}
|
||||
{...videoAutoplayAttributes}
|
||||
|
||||
@ -7,7 +7,7 @@ import { distinctUntilChanged, filter, map, startWith } from 'rxjs/operators'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
|
||||
import { LoadingSpinner, BeforeUnloadPrompt } from '@sourcegraph/wildcard'
|
||||
import { BeforeUnloadPrompt, LoadingSpinner } from '@sourcegraph/wildcard'
|
||||
|
||||
import settingsSchemaJSON from '../../../../schema/settings.schema.json'
|
||||
import { SaveToolbar } from '../components/SaveToolbar'
|
||||
@ -140,12 +140,7 @@ export class SettingsFile extends React.PureComponent<Props, State> {
|
||||
this.state.contents === undefined ? this.getPropsSettingsContentsOrEmpty() : this.state.contents
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'test-settings-file percy-hide d-flex flex-grow-1 flex-column',
|
||||
styles.settingsFile
|
||||
)}
|
||||
>
|
||||
<div className={classNames('test-settings-file d-flex flex-grow-1 flex-column', styles.settingsFile)}>
|
||||
<BeforeUnloadPrompt when={this.state.saving || this.dirty} message="Discard settings changes?" />
|
||||
<React.Suspense fallback={<LoadingSpinner className="mt-2" />}>
|
||||
<MonacoSettingsEditor
|
||||
|
||||
@ -12,7 +12,6 @@ This markdown is used to generate an annotation at the top of every build, displ
|
||||
<li><strong>GraphQL</strong> GraphQL is a data query and manipulation language for APIs, and a runtime for executing those queries with your existing data.</li>
|
||||
<li><strong>Jest</strong> is a JavaScript testing framework developed by Facebook, which provides complete and easy-to-set-up testing functionality.</li>
|
||||
<li><strong>Mocha</strong> is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun.</li>
|
||||
<li><strong>Percy</strong> is a visual testing and review platform that enables teams to catch visual changes across web apps, static sites, component libraries, and more.</li>
|
||||
<li><strong>Puppeteer</strong> is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol, enabling tasks such as generating screenshots and PDFs of pages.</li>
|
||||
<li><strong>ESBuild</strong> is an extremely fast JavaScript bundler and minifier, primarily designed for speed and performance.</li>
|
||||
<li><strong>ESLint</strong> is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs.</li>
|
||||
|
||||
@ -18,7 +18,6 @@ var clientRootFiles = append(pnpmFiles, []string{
|
||||
"postcss.config.js",
|
||||
"tsconfig.base.json",
|
||||
"tsconfig.json",
|
||||
".percy.yml",
|
||||
".eslintrc.js",
|
||||
}...)
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@ package ci
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
bk "github.com/sourcegraph/sourcegraph/dev/ci/internal/buildkite"
|
||||
"github.com/sourcegraph/sourcegraph/dev/ci/internal/ci/operations"
|
||||
@ -16,12 +15,7 @@ func addStylelint(pipeline *bk.Pipeline) {
|
||||
|
||||
var browsers = []string{"chrome"}
|
||||
|
||||
func getParallelTestCount(webParallelTestCount int) int {
|
||||
return webParallelTestCount + len(browsers)
|
||||
}
|
||||
|
||||
func addBrowserExtensionIntegrationTests(parallelTestCount int) operations.Operation {
|
||||
testCount := getParallelTestCount(parallelTestCount)
|
||||
func addBrowserExtensionIntegrationTests() operations.Operation {
|
||||
return func(pipeline *bk.Pipeline) {
|
||||
for _, browser := range browsers {
|
||||
pipeline.AddStep(
|
||||
@ -32,8 +26,6 @@ func addBrowserExtensionIntegrationTests(parallelTestCount int) operations.Opera
|
||||
bk.Env("LOG_BROWSER_CONSOLE", "false"),
|
||||
bk.Env("SOURCEGRAPH_BASE_URL", "https://sourcegraph.com"),
|
||||
bk.Env("POLLYJS_MODE", "replay"), // ensure that we use existing recordings
|
||||
bk.Env("PERCY_ON", "true"),
|
||||
bk.Env("PERCY_PARALLEL_TOTAL", strconv.Itoa(testCount)),
|
||||
bk.Cmd("pnpm install --frozen-lockfile --fetch-timeout 60000"),
|
||||
bk.Cmd("pnpm --filter @sourcegraph/browser run build"),
|
||||
bk.Cmd("pnpm run test-browser-integration"),
|
||||
|
||||
@ -70,9 +70,7 @@ func GeneratePipeline(c Config) (*bk.Pipeline, error) {
|
||||
}
|
||||
bk.FeatureFlags.ApplyEnv(env)
|
||||
|
||||
// On release branches Percy must compare to the previous commit of the release branch, not main.
|
||||
if c.RunType.Is(runtype.ReleaseBranch, runtype.TaggedRelease, runtype.InternalRelease) {
|
||||
env["PERCY_TARGET_BRANCH"] = c.Branch
|
||||
// When we are building a release, we do not want to cache the client bundle.
|
||||
//
|
||||
// This is a defensive measure, as caching the client bundle is tricky when it comes to invalidating it.
|
||||
@ -155,7 +153,7 @@ func GeneratePipeline(c Config) (*bk.Pipeline, error) {
|
||||
|
||||
if c.Diff.Has(changed.ClientBrowserExtensions) {
|
||||
ops.Merge(operations.NewNamedSet("Browser Extensions",
|
||||
addBrowserExtensionIntegrationTests(0), // we pass 0 here as we don't have other pipeline steps to contribute to the resulting Percy build
|
||||
addBrowserExtensionIntegrationTests(),
|
||||
))
|
||||
}
|
||||
|
||||
@ -166,7 +164,7 @@ func GeneratePipeline(c Config) (*bk.Pipeline, error) {
|
||||
CoreTestOperationsOptions{
|
||||
IsMainBranch: buildOptions.Branch == "main",
|
||||
},
|
||||
addBrowserExtensionIntegrationTests(0), // we pass 0 here as we don't have other pipeline steps to contribute to the resulting Percy build
|
||||
addBrowserExtensionIntegrationTests(),
|
||||
wait,
|
||||
addBrowserExtensionReleaseSteps)
|
||||
|
||||
|
||||
@ -10,4 +10,4 @@ echo "--- Pnpm install in root"
|
||||
./dev/ci/pnpm-install-with-retry.sh
|
||||
|
||||
echo "--- Run integration test suite"
|
||||
pnpm percy exec --quiet -- pnpm _test-integration "$@"
|
||||
pnpm pnpm _test-integration "$@"
|
||||
|
||||
@ -29,7 +29,7 @@ NON_BUNDLED_DEPS = [
|
||||
"//:node_modules/axe-core",
|
||||
]
|
||||
|
||||
def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, is_percy_enabled = False, **kwargs):
|
||||
def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, **kwargs):
|
||||
bundle_name = "%s_bundle" % name
|
||||
|
||||
# Bundle the tests to remove the use of esm modules in tests
|
||||
@ -71,7 +71,6 @@ def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, is_percy_
|
||||
# - GH_TOKEN
|
||||
# - DISPLAY
|
||||
# - HEADLESS
|
||||
# - PERCY_TOKEN
|
||||
env = dict(env, **{
|
||||
# Add environment variable so that mocha writes its test xml
|
||||
# to the location Bazel expects.
|
||||
@ -93,33 +92,10 @@ def mocha_test(name, tests, deps = [], args = [], data = [], env = {}, is_percy_
|
||||
"INTEGRATION_TESTS": "true",
|
||||
})
|
||||
|
||||
if is_percy_enabled:
|
||||
js_test(
|
||||
name = name,
|
||||
args = args,
|
||||
env = dict(env, **{
|
||||
"PERCY_ON": "true",
|
||||
}),
|
||||
data = data + [
|
||||
"//:node_modules/@percy/cli",
|
||||
"//:node_modules/@percy/puppeteer",
|
||||
"//:node_modules/mocha",
|
||||
"//:node_modules/resolve-bin",
|
||||
"//client/shared/dev:run_mocha_tests_with_percy",
|
||||
],
|
||||
# Executed mocha tests with Percy enabled via `percy exec -- mocha ...`
|
||||
# Prepends volatile env variables to the command to make Percy aware of the
|
||||
# current git branch and commit.
|
||||
entry_point = "//client/shared/dev:run_mocha_tests_with_percy",
|
||||
flaky = kwargs.pop("flaky"),
|
||||
timeout = kwargs.pop("timeout"),
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
mocha_bin.mocha_test(
|
||||
name = name,
|
||||
args = args,
|
||||
data = data,
|
||||
env = env,
|
||||
**kwargs
|
||||
)
|
||||
mocha_bin.mocha_test(
|
||||
name = name,
|
||||
args = args,
|
||||
data = data,
|
||||
env = env,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@ -368,7 +368,6 @@ mocha_test(
|
||||
env = {
|
||||
"WEB_BUNDLE_PATH": "$(rootpath //client/web:bundle)",
|
||||
},
|
||||
is_percy_enabled = True,
|
||||
tags = [
|
||||
"no-sandbox",
|
||||
"requires-network",
|
||||
@ -385,23 +384,11 @@ for implementation details.
|
||||
|
||||
We use the `esbuild()` rule from Aspect rules to bundle JS test files removing import statements. Here, the `external` parameter is set to `NON_BUNDLED` to prevent certain dependencies from being included in the bundle, since these are either managed by Mocha or have issues being bundled.
|
||||
|
||||
2. If Percy is not enabled we just need to run the Mocha CLI with certain arguments.
|
||||
2. We need to run the Mocha CLI with certain arguments.
|
||||
|
||||
The `args` parameter is populated with Mocha configurations such as the path to the Mocha config file, the path to the generated test bundles, and the number of retries. The `data`` parameter is also expanded to include non-bundled dependencies and the bundle itself.
|
||||
`data` represents files which should be available on the dist during the action execution.
|
||||
|
||||
3. If Percy is enabled we run a customer Javascript script that runs Mocha tests with Percy and sets required env variables.
|
||||
|
||||
The reason why the setup here is complicated is that Percy builds need to know the current commit and branch name which busts Bazel cache and we do not want to run integration tests on every commit. To avoid busting Bazel cache we rely on stamping.
|
||||
|
||||
- [Stamping](https://bazel.build/reference/glossary#stamping): Stamping is a method in Bazel for embedding various build-time variables into the final binary or rule outputs. It is typically used to incorporate data like the current Git commit SHA or build number into the output. `stamp = 1` indicates that the build stamping is enabled for the `js_run_binary` rule.
|
||||
- [js_run_binary](https://docs.aspect.build/rules/aspect_rules_js/docs/js_run_binary): The `js_run_binary` rule is used to execute JavaScript programs using Node.js as a part of the build process. It's designed to work with Bazel's hermeticity, meaning the build process won't be affected by the external system state.
|
||||
- [build_test](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/build_test_doc.md): `build_test` is a simple rule from Bazel Skylib that asserts certain properties about the build. It can be used to check if certain targets are present or absent, to ensure certain properties are maintained in the build configuration, or even to check if certain targets are error-free.
|
||||
|
||||
In `mocha_test`, the `js_run_binary` is used in combination with `build_test` to create a specific setup for running Mocha tests with Percy enabled. The same could be achieved only with one target `js_test` but it does not support stamping, which is needed here to pass certain build-time variables (like the Git branch and commit hash) to Percy. These variables are required for Percy to correctly create and associate visual diff reports. The output of `js_run_binary` is then used as a target for `build_test` to ensure the binary runs correctly.
|
||||
|
||||
The volatile env variables (`BUILDKITE_COMMIT` and `BUILDKITE_BRANCH`), which are generated by `dev/bazel_buildkite_stamp_vars.sh` are then used by the Node.js script (`client/shared/dev/runMochaTestsWithPercy.js`) as env variables in the Percy CLI command.
|
||||
|
||||
## ESLint custom rule implementation for type-aware linting
|
||||
|
||||
- TODO: npm_translate_lock with public_hoist_packages in the WORKSPACE file
|
||||
|
||||
@ -76,7 +76,6 @@ Tradeoffs:
|
||||
Examples:
|
||||
|
||||
- Tests that call our search API to test the behavior of our entire search system.
|
||||
- Tests that validate UI styles, through [visual testing](#visual-testing).
|
||||
- Tests that validate UI behavior in the browser while mocking out all network requests so no backend is required.
|
||||
- Note: We still typically prefer unit tests here, only fall back to integration tests if you need to test some very specific behavior that cannot be covered in a unit test.
|
||||
|
||||
@ -101,12 +100,6 @@ Examples:
|
||||
- Run our Sourcegraph Docker image and verify that site admins can complete the registration flow.
|
||||
- Run our Sourcegraph Docker image and verify that users can sign in and perform a search.
|
||||
|
||||
#### Visual testing
|
||||
|
||||
Visual testing is useful to catch visual regressions and verify designs for new features. [More info about visual testing philosophy](testing_web_code.md#visual-regressions)
|
||||
|
||||
We use [Percy](https://percy.io/) to detect visual changes in Sourcegraph features during browser-based tests (client integration tests and end-to-end tests). You may need permissions to update screenshots if your feature introduces visual changes. Post a message in #dev-chat that you need access to Percy, and someone will add you to our organization (you will also receive an invitation via e-mail). Once you've been invited to the Sourcegraph organization and created a Percy account, you should then link it to your GitHub account.
|
||||
|
||||
### Other testing strategies
|
||||
|
||||
- Targeted [code reviews](pull_request_reviews.md) can help ensure changes are appropriately tested.
|
||||
|
||||
@ -20,11 +20,6 @@ This is the implementation of our [Testing Principles](testing_principles.md) fo
|
||||
When testing UI, there are several categories of things that should be tested.
|
||||
These categories may be more or less important depending on the piece of UI.
|
||||
|
||||
### Visual regressions
|
||||
|
||||
A visual regression is a bug where the component behaves correctly, but no longer looks as intended.
|
||||
Percy can take screenshots in end-to-end tests and client integration tests.
|
||||
|
||||
### Render output
|
||||
|
||||
Depending on the component, it can be important to test the _render output_ of the component.
|
||||
|
||||
@ -389,54 +389,6 @@ You can execute more complex interactions atomically _within the browser_ using
|
||||
Note that the passed callback cannot refer to any scope variables as it is executed in the browser.
|
||||
It can however be passed JSON-stringifyable parameters and return a JSON-stringifyable return value.
|
||||
|
||||
### Testing visual regressions
|
||||
|
||||
#### Reviewing visual changes in a PR
|
||||
|
||||
When you submit a PR, a check from https://percy.io/Sourcegraph/Sourcegraph will appear:
|
||||
|
||||

|
||||
|
||||
If Percy failed CI ❌ then click on the **Details** link to review the visual changes:
|
||||
|
||||

|
||||
|
||||
Click the image on the right to toggle between diff and full image mode to review the change. Diff mode shows the changes in red.
|
||||
|
||||
If the changes are intended, click **Approve** 👍
|
||||
|
||||
Once you approve all of the changes, the Percy check will turn green ✅
|
||||
|
||||
#### Running the tests locally
|
||||
|
||||
It is possible to run our Percy visual regression tests locally.
|
||||
|
||||
1. Get `PERCY_TOKEN` from 1Password [here](https://team-sourcegraph.1password.com/vaults/dnrhbauihkhjs5ag6vszsme45a/allitems/wo7p6waf5jtqayl2vkynonxspy).
|
||||
1. Run your integration tests with the following prefix before your command: `PERCY_ON=true PERCY_TOKEN=<copied-token> ./node_modules/.bin/percy exec --`
|
||||
1. Once the tests finish, Percy should output a URL to the created build.
|
||||
|
||||
#### Adding a new visual snapshot test
|
||||
|
||||
Open an existing appropiate browser-based test file (end-to-end or integration) or create a new one.
|
||||
You can take screenshot in any test by calling `percySnapshot()`:
|
||||
|
||||
```TypeScript
|
||||
test('Repositories list', async function () {
|
||||
await page.goto(baseURL + '/site-admin/repositories?query=gorilla%2Fmux')
|
||||
await page.waitForSelector('[test-repository-name="/github.com/gorilla/mux"]', { visible: true })
|
||||
await percySnapshot(page, this.currentTest!.fullTitle())
|
||||
})
|
||||
```
|
||||
|
||||
When running in CI, this will take a screenshot of the web page at that point in time in the test and upload it to Percy.
|
||||
When you submit the PR, Percy will fail until you approve the new snapshot.
|
||||
|
||||
#### Flakiness in snapshot tests
|
||||
|
||||
Flakiness in snapshot tests can be caused by the search response time, order of results, animations, premature snapshots while the page is still loading, etc.
|
||||
|
||||
This can be solved with [Percy specific CSS](https://docs.percy.io/docs/percy-specific-css) that will be applied only when taking the snapshot and allow you to hide flaky elements with `display: none`. In simple cases, you can simply apply the `percy-hide` (to apply `visibility: hidden`) or `percy-display-none` (to apply `display: none`) CSS classes to the problematic element and it will be hidden from Percy.
|
||||
|
||||
### Accessibility tests
|
||||
|
||||
We use [axe-core](https://github.com/dequelabs/axe-core) to run accessibility audits through our integration tests. It ensures we can quickly assess entire pages and raise any errors before they become problems in production.
|
||||
@ -481,9 +433,6 @@ The breakdown of known client flakes by type with resolution tips:
|
||||
|
||||
#### Visual regression flakes
|
||||
|
||||
_Problem:_ Percy’s pixel sensitivity is too high, and we cannot relax it further which means that SVG rendering can be flaky.
|
||||
_Solution:_ Hide flaky elements from Percy using the `.percy-hide` class name.
|
||||
|
||||
_Problem:_ UI depends on the date and time, which are not appropriately mocked.
|
||||
_Solution:_ Mock the date and time properly in your integration test or Storybook story.
|
||||
|
||||
@ -504,12 +453,3 @@ _Problem examples:_
|
||||
2. `TimeoutError: waiting for selector '.theme.theme-dark' failed: timeout 30000ms exceeded`
|
||||
|
||||
_Solution:_ These should be disabled immediately and fixed later by owning teams.
|
||||
|
||||
#### Percy outages
|
||||
|
||||
_Problem:_ Percy API outages result into
|
||||
|
||||
1. HTTP requests to upload screenshots fail with internal server errors.
|
||||
2. HTTP requests to upload screenshots fail with errors about duplicated snapshot names. `[percy] Error: The name of each snapshot must be unique, and this name already exists in the build`
|
||||
|
||||
_Solution:_ Wait for the Percy infrastructure to come back to life and restart the build. 🥲
|
||||
|
||||
@ -73,8 +73,6 @@
|
||||
"@graphql-codegen/typescript-operations": "2.5.10",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^3.7.1",
|
||||
"@octokit/rest": "^16.36.0",
|
||||
"@percy/cli": "^1.24.0",
|
||||
"@percy/puppeteer": "^2.0.2",
|
||||
"@pollyjs/adapter": "^5.0.0",
|
||||
"@pollyjs/core": "^5.1.0",
|
||||
"@pollyjs/persister-fs": "^5.0.0",
|
||||
@ -449,11 +447,6 @@
|
||||
"node-gyp": "*"
|
||||
}
|
||||
},
|
||||
"@percy/sdk-utils": {
|
||||
"dependencies": {
|
||||
"ws": "*"
|
||||
}
|
||||
},
|
||||
"mz": {
|
||||
"dependencies": {
|
||||
"graceful-fs": "*"
|
||||
|
||||
186
pnpm-lock.yaml
186
pnpm-lock.yaml
@ -10,7 +10,7 @@ overrides:
|
||||
cssnano: 4.1.10
|
||||
tslib: 2.1.0
|
||||
|
||||
packageExtensionsChecksum: f2efae6ae360a154188d7bdc16a0ca69
|
||||
packageExtensionsChecksum: 9afbef0948214d563f55ebbc2e930855
|
||||
|
||||
importers:
|
||||
|
||||
@ -521,12 +521,6 @@ importers:
|
||||
'@octokit/rest':
|
||||
specifier: ^16.36.0
|
||||
version: 16.36.0
|
||||
'@percy/cli':
|
||||
specifier: ^1.24.0
|
||||
version: 1.24.0
|
||||
'@percy/puppeteer':
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2(puppeteer@13.7.0)
|
||||
'@pollyjs/adapter':
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
@ -6848,182 +6842,6 @@ packages:
|
||||
webcrypto-core: 1.7.5
|
||||
dev: true
|
||||
|
||||
/@percy/cli-app@1.24.0:
|
||||
resolution: {integrity: sha512-z7ksv+SvdgDuAZ4WDnluuLuS72xb18DKauuwikSKipdICHHFQuXdRc0ngloADC/6IFzp0JhiukiRanntbBkPvg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/cli-command': 1.24.0
|
||||
'@percy/cli-exec': 1.24.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli-build@1.24.0:
|
||||
resolution: {integrity: sha512-p/wmO0OzqJ2Uou7QNAdxioqKmxu7U+6Al02GvVhYcPja/MkVjfJT/jDl+XstXawR76txQW9QWrNsK5YOAWUupQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/cli-command': 1.24.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli-command@1.24.0:
|
||||
resolution: {integrity: sha512-n4qyDdUc+TiX/YykGg59IS1DBmm4UdA7ZaiTdw/D5AZohzwwVbwL+Q4QMYqcohtfYZ/F8UT7Qy3Jma3+YKTnxw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@percy/config': 1.24.0
|
||||
'@percy/core': 1.24.0
|
||||
'@percy/logger': 1.24.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli-config@1.24.0:
|
||||
resolution: {integrity: sha512-7T70Y3vC0hIGBe+WOmdzspN8N5uflBRwuPoRXn2PdzxvH55hUhCGFT/Wxb8C6rTMJ9k++POkxMoQaSErVANYYg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/cli-command': 1.24.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli-exec@1.24.0:
|
||||
resolution: {integrity: sha512-T5B8HLjPde0js5lkO14uk02QZKmgxILjALh5SX9VFL2Qx4cUXw+A29epPPv6OLI2x2oww8e5nTdlnmykX8n4kQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/cli-command': 1.24.0
|
||||
cross-spawn: 7.0.3
|
||||
which: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli-snapshot@1.24.0:
|
||||
resolution: {integrity: sha512-zxoE1SbdTvUlP7QAjTs7+M7U8cHEDF1ec7ov06m1i+bul68YhZ0S+P4a1Mbt6oWBsAxjYz06h4jnq32JitbSDg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/cli-command': 1.24.0
|
||||
yaml: 2.4.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli-upload@1.24.0:
|
||||
resolution: {integrity: sha512-/4XNzMAhbccYSsPhw/KWRVjnd13nd17LB178dVNX4UEtaETDbBF+VZSlU3scgs8mlpuqY8b8bHDaSJNfI71UwQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/cli-command': 1.24.0
|
||||
fast-glob: 3.3.2
|
||||
image-size: 1.1.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/cli@1.24.0:
|
||||
resolution: {integrity: sha512-n8dxQfA2GoPk468EQ+sO7P/P5sBl3Q+s7UrljQhf4wPt4l+CBmoxMML8Ib71MyISzwxY7bOSw2QMr26r6n06/A==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@percy/cli-app': 1.24.0
|
||||
'@percy/cli-build': 1.24.0
|
||||
'@percy/cli-command': 1.24.0
|
||||
'@percy/cli-config': 1.24.0
|
||||
'@percy/cli-exec': 1.24.0
|
||||
'@percy/cli-snapshot': 1.24.0
|
||||
'@percy/cli-upload': 1.24.0
|
||||
'@percy/client': 1.24.0
|
||||
'@percy/logger': 1.24.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/client@1.24.0:
|
||||
resolution: {integrity: sha512-mCMIGryE+0oxJN6v+riZ+XqnubEL9rajLOJI7xNOj5gNBNNvwgvkpTiNId9d6LNZVhA7dN9ZHTW+zFK+i4nU8A==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/env': 1.24.0
|
||||
'@percy/logger': 1.24.0
|
||||
dev: true
|
||||
|
||||
/@percy/config@1.24.0:
|
||||
resolution: {integrity: sha512-FOV8VkW/MjLI7PXzKSjxFBK7z0ND1s8LtXuLQNIrux3oiCKHIVBAQWIV86LLnXSSn+G5i3tfQua9YED5ATyNFQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@percy/logger': 1.24.0
|
||||
ajv: 8.11.2
|
||||
cosmiconfig: 7.0.1
|
||||
yaml: 2.4.1
|
||||
dev: true
|
||||
|
||||
/@percy/core@1.24.0:
|
||||
resolution: {integrity: sha512-wys1k3RmENOWT4MeS2+8yGHNqzYuy64lqPi36dFoHwZHzSGHH52+6EPPDb+gXLFIxBUHVTwbdaNimstIO3F9Ww==}
|
||||
engines: {node: '>=14'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@percy/client': 1.24.0
|
||||
'@percy/config': 1.24.0
|
||||
'@percy/dom': 1.24.0
|
||||
'@percy/logger': 1.24.0
|
||||
content-disposition: 0.5.4
|
||||
cross-spawn: 7.0.3
|
||||
extract-zip: 2.0.1
|
||||
fast-glob: 3.3.2
|
||||
micromatch: 4.0.5
|
||||
mime-types: 2.1.35
|
||||
path-to-regexp: 6.2.0
|
||||
rimraf: 3.0.2
|
||||
ws: 8.16.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/dom@1.24.0:
|
||||
resolution: {integrity: sha512-URMLvsOPkCKayx/Wtyj5IymmIhzrtf4en6IKeW2sSTsm7X+kJQ+3wOa3017mX3HXJPIS5xEJKpiCR7hP9BtcUA==}
|
||||
dev: true
|
||||
|
||||
/@percy/env@1.24.0:
|
||||
resolution: {integrity: sha512-fUUWWDZJ71kv+Po5yOaoS8t7eLmQL5NN6hqRdLhgqN9PZnu+OKIGaeK1GNaTWiHL9+zANRBc1pZjQWhRlleWVA==}
|
||||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/@percy/logger@1.24.0:
|
||||
resolution: {integrity: sha512-yaAo08FMED1o8jZycTEnTob1CZIVGaNluJc4R9fCRw7wWS88IAu4F9sdbzUZQZwZ/QGvtfI+55dNQaaesk69Bw==}
|
||||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/@percy/puppeteer@2.0.2(puppeteer@13.7.0):
|
||||
resolution: {integrity: sha512-DPyh5UyttPPXMNl3o6Owox7bnV54aQ7sIWfcsXUBZ6q1wLVmBjc5KP4x51dpPiuTDn3SMzFExMrXBFugfDJHPA==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
puppeteer: '>=1'
|
||||
dependencies:
|
||||
'@percy/sdk-utils': 1.24.0
|
||||
puppeteer: 13.7.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@percy/sdk-utils@1.24.0:
|
||||
resolution: {integrity: sha512-kfYxX0rHP5N2Da6HyfjRCVaeNahAO9XV5WD4SKWKKjdKVkV/Z5/XjVgSKlTBLSYxnWDzYJJ4UHZV43Mw+facMA==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
ws: 8.16.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@phenomnomnominal/tsquery@4.0.0(typescript@5.4.2):
|
||||
resolution: {integrity: sha512-s2Yet/MCj9Jh6nR6GfldrUPT6Y+aM1jIAdiKcOKEzmeKALT0Tc7SFIkYP3KvzjzbkKK5W7BiJ3cWy2UOa4ITbw==}
|
||||
peerDependencies:
|
||||
@ -18907,6 +18725,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
queue: 6.0.2
|
||||
dev: false
|
||||
|
||||
/immediate@3.0.6:
|
||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||
@ -23361,6 +23180,7 @@ packages:
|
||||
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
dev: false
|
||||
|
||||
/quick-lru@4.0.1:
|
||||
resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
|
||||
|
||||
@ -1858,8 +1858,7 @@ tests:
|
||||
bazel-web-integration:
|
||||
cmd: |
|
||||
export GH_TOKEN=$(gcloud secrets versions access latest --secret=GITHUB_TOKEN --quiet --project=sourcegraph-ci)
|
||||
export PERCY_TOKEN=$(gcloud secrets versions access latest --secret=PERCY_TOKEN --quiet --project=sourcegraph-ci)
|
||||
bazel test //client/web/src/integration:integration-tests --test_env=HEADLESS=false --test_env=SOURCEGRAPH_BASE_URL="http://localhost:7080" --test_env=GH_TOKEN=$GH_TOKEN --test_env=DISPLAY=$DISPLAY --test_env=PERCY_TOKEN=$PERCY_TOKEN
|
||||
bazel test //client/web/src/integration:integration-tests --test_env=HEADLESS=false --test_env=SOURCEGRAPH_BASE_URL="http://localhost:7080" --test_env=GH_TOKEN=$GH_TOKEN --test_env=DISPLAY=$DISPLAY
|
||||
|
||||
backend-integration:
|
||||
cmd: cd dev/gqltest && go test -long -base-url $BASE_URL -email $EMAIL -username $USERNAME -password $PASSWORD ./gqltest
|
||||
|
||||
@ -313,22 +313,6 @@ PNPM,@opentelemetry/semantic-conventions,1.9.1,Apache 2.0,"",Approved
|
||||
PNPM,@peculiar/asn1-schema,2.3.3,MIT,"",Approved
|
||||
PNPM,@peculiar/json-schema,1.1.12,MIT,"",Approved
|
||||
PNPM,@peculiar/webcrypto,1.4.1,MIT,"",Approved
|
||||
PNPM,@percy/cli,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-app,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-build,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-command,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-config,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-exec,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-snapshot,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/cli-upload,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/client,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/config,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/core,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/dom,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/env,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/logger,1.24.0,MIT,"",Approved
|
||||
PNPM,@percy/puppeteer,2.0.2,MIT,"",Approved
|
||||
PNPM,@percy/sdk-utils,1.24.0,MIT,"",Approved
|
||||
PNPM,@phenomnomnominal/tsquery,4.0.0,MIT,"",Approved
|
||||
PNPM,@pkgjs/parseargs,0.11.0,MIT,"",Approved
|
||||
PNPM,@playwright/test,1.25.0,Apache 2.0,"",Approved
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user