2
.github/workflows/headless-tests.yml
vendored
2
.github/workflows/headless-tests.yml
vendored
@@ -2,7 +2,7 @@ name: Headless Tests
|
||||
|
||||
# **What it does**: This runs our browser tests to test things that depend
|
||||
# on client-side JavaScript.
|
||||
# **Why we have it**: Because most automated jest tests only test static
|
||||
# **Why we have it**: Because most automated vitest tests only test static
|
||||
# input and outputs.
|
||||
# **Who does it impact**: Docs engineering, open-source engineering contributors.
|
||||
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -19,7 +19,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
# Setting this will activate the jest tests that depend on actually
|
||||
# Setting this will activate the vitest tests that depend on actually
|
||||
# sending real search queries to Elasticsearch
|
||||
ELASTICSEARCH_URL: http://localhost:9200/
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Your JWT must be signed using the `RS256` algorithm and must contain the followi
|
||||
|---|---|---|
|
||||
|`iat`| Issued At | The time that the JWT was created. To protect against clock drift, we recommend that you set this 60 seconds in the past and ensure that your server's date and time is set accurately (for example, by using the Network Time Protocol). |
|
||||
|`exp`| Expires At | The expiration time of the JWT, after which it can't be used to request an installation token. The time must be no more than 10 minutes into the future. |
|
||||
|`iss`| Issuer | The ID of your {% data variables.product.prodname_github_app %}. This value is used to find the right public key to verify the signature of the JWT. You can find your app's ID on the settings page for your {% data variables.product.prodname_github_app %}. For more information about navigating to the settings page for your {% data variables.product.prodname_github_app %}, see "[AUTOTITLE](https://github.com/github/docs/blob/main/content/apps/maintaining-github-apps/modifying-a-github-app-registration#navigating-to-your-github-app-settings)." For more information, see "[Apps](/rest/apps/apps)" in the REST API documentation.|
|
||||
|`iss`| Issuer | The ID of your {% data variables.product.prodname_github_app %}. This value is used to find the right public key to verify the signature of the JWT. You can find your app's ID on the settings page for your {% data variables.product.prodname_github_app %}. For more information about navigating to the settings page for your {% data variables.product.prodname_github_app %}, see "[AUTOTITLE](/apps/maintaining-github-apps/modifying-a-github-app-registration#navigating-to-your-github-app-settings)."|
|
||||
|`alg`| Message authentication code algorithm | This should be `RS256` since your JWT must be signed using the `RS256` algorithm. |
|
||||
|
||||
To use a JWT, pass it in the `Authorization` header of an API request. For example:
|
||||
|
||||
1330
package-lock.json
generated
1330
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@@ -35,7 +35,7 @@
|
||||
"index-test-fixtures": "npm run index-elasticsearch -- -l en -l ja -V ghec -V dotcom --index-prefix tests -- src/search/tests/fixtures/search-indexes",
|
||||
"lint": "eslint '**/*.{js,mjs,ts,tsx}'",
|
||||
"lint-content": "node src/content-linter/scripts/lint-content.js",
|
||||
"lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest src/content-linter/tests/lint-files.js",
|
||||
"lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules vitest src/content-linter/tests/lint-files.js",
|
||||
"generate-code-scanning-query-list": "tsx src/code-scanning/scripts/generate-code-scanning-query-list.ts",
|
||||
"generate-content-linter-docs": "tsx src/content-linter/scripts/generate-docs.ts",
|
||||
"move-content": "node src/content-render/scripts/move-content.js",
|
||||
@@ -63,10 +63,9 @@
|
||||
"sync-search-indices": "node src/search/scripts/sync-search-indices.js",
|
||||
"sync-search-server": "cross-env NODE_ENV=production PORT=4002 MINIMAL_RENDER=true CHANGELOG_DISABLED=true tsx src/frame/server.ts",
|
||||
"sync-webhooks": "src/rest/scripts/update-files.js -o webhooks",
|
||||
"test": "cross-env NODE_OPTIONS='--max_old_space_size=4096 --experimental-vm-modules' jest --logHeapUsage",
|
||||
"test": "cross-env NODE_OPTIONS='--max_old_space_size=4096 --experimental-vm-modules' vitest",
|
||||
"test-local-dev": "node src/workflows/test-local-dev.js",
|
||||
"test-moved-content": "tsx src/content-render/scripts/test-moved-content.ts",
|
||||
"test-watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch --notify --notifyMode=change --coverage",
|
||||
"tsc": "tsc --noEmit",
|
||||
"unallowed-contributions": "node src/workflows/unallowed-contributions.js",
|
||||
"update-data-and-image-paths": "node src/early-access/scripts/update-data-and-image-paths.js",
|
||||
@@ -153,14 +152,6 @@
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/tests/**/*.js"
|
||||
],
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"**/*.tsx",
|
||||
@@ -197,41 +188,6 @@
|
||||
"src/code-scanning/scripts/generate-code-scanning-query-list.ts"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"testTimeout": 30000,
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"branches": 95,
|
||||
"functions": 95,
|
||||
"lines": 95,
|
||||
"statements": -5
|
||||
}
|
||||
},
|
||||
"globalSetup": "./src/tests/scripts/start-server-for-jest.js",
|
||||
"globalTeardown": "./src/tests/scripts/kill-server-for-jest.js",
|
||||
"moduleNameMapper": {
|
||||
"@primer/behaviors": "<rootDir>/node_modules/@primer/behaviors/dist/cjs/index.js"
|
||||
},
|
||||
"preset": "ts-jest",
|
||||
"reporters": [
|
||||
"default",
|
||||
"github-actions"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"./src/tests/jest.setup.js",
|
||||
"jest-expect-message"
|
||||
],
|
||||
"testEnvironment": "node",
|
||||
"testMatch": [
|
||||
"**/tests/**/*.js"
|
||||
],
|
||||
"testPathIgnorePatterns": [
|
||||
"node_modules/",
|
||||
"vendor/",
|
||||
"src/fixtures/fixtures/",
|
||||
"src/tests/helpers/"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "8.11.0",
|
||||
"@github/failbot": "0.8.3",
|
||||
@@ -383,6 +339,7 @@
|
||||
"typescript": "^5.4.4",
|
||||
"unist-util-remove": "^4.0.0",
|
||||
"unist-util-visit-parents": "6.0.1",
|
||||
"vitest": "1.5.0",
|
||||
"website-scraper": "^5.3.1"
|
||||
},
|
||||
"overrides": {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { describe, jest, test } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import enterpriseServerReleases from '#src/versions/lib/enterprise-server-releases.js'
|
||||
import { get, getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
import { SURROGATE_ENUMS } from '#src/frame/middleware/set-fastly-surrogate-key.js'
|
||||
|
||||
describe('enterprise deprecation', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('redirects language-prefixed requests for deprecated enterprise content', async () => {
|
||||
const res = await get('/en/enterprise/2.12')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { jest } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import sharp from 'sharp'
|
||||
import { fileTypeFromBuffer } from 'file-type'
|
||||
|
||||
@@ -6,7 +7,7 @@ import { SURROGATE_ENUMS } from '#src/frame/middleware/set-fastly-surrogate-key.
|
||||
import { get, head } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('dynamic assets', () => {
|
||||
jest.setTimeout(3 * 60 * 1000)
|
||||
vi.setConfig({ testTimeout: 3 * 60 * 1000 })
|
||||
|
||||
test('GET PNG as a WebP', async () => {
|
||||
const res = await get('/assets/images/_fixtures/screenshot.webp', {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest'
|
||||
import nock from 'nock'
|
||||
import { expect, jest } from '@jest/globals'
|
||||
|
||||
import { checkCachingHeaders } from '#src/tests/helpers/caching-headers.js'
|
||||
import { setDefaultFastlySurrogateKey } from '#src/frame/middleware/set-fastly-surrogate-key.js'
|
||||
@@ -57,7 +57,7 @@ describe('archived enterprise static assets', () => {
|
||||
// Sometimes static assets are proxied. The URL for the static asset
|
||||
// might not indicate it's based on archived enterprise version.
|
||||
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
beforeAll(async () => {
|
||||
// The first page load takes a long time so let's get it out of the way in
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import { jest, expect } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { get } from '#src/tests/helpers/e2etest.js'
|
||||
import { checkCachingHeaders } from '#src/tests/helpers/caching-headers.js'
|
||||
@@ -14,7 +14,7 @@ function getNextStaticAsset(directory) {
|
||||
}
|
||||
|
||||
describe('static assets', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('should serve /assets/cb-* with optimal headers', async () => {
|
||||
const res = await get('/assets/cb-1234/images/site/logo.png')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
import { allVersions } from '#src/versions/lib/all-versions.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import {
|
||||
filterByAllowlistValues,
|
||||
filterAndUpdateGhesDataByAllowlistValues,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { supported } from '#src/versions/lib/enterprise-server-releases.js'
|
||||
import { allVersionKeys, allVersions } from '#src/versions/lib/all-versions.js'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readFileSync } from 'fs'
|
||||
|
||||
import cheerio from 'cheerio'
|
||||
import { jest, test } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { loadPages } from '#src/frame/lib/page-data.js'
|
||||
import { get } from '#src/tests/helpers/e2etest.js'
|
||||
@@ -10,7 +10,7 @@ import { get } from '#src/tests/helpers/e2etest.js'
|
||||
const pageList = await loadPages(undefined, ['en'])
|
||||
|
||||
describe('autogenerated docs render', () => {
|
||||
jest.setTimeout(3 * 60 * 1000)
|
||||
vi.setConfig({ testTimeout: 3 * 60 * 1000 })
|
||||
|
||||
const autogeneratedPages = pageList.filter((page) => page.autogenerated)
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { tmpdir } from 'os'
|
||||
import { mkdirp } from 'mkdirp'
|
||||
import { cp, rm, readFile } from 'fs/promises'
|
||||
import { existsSync } from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
import { mkdirp } from 'mkdirp'
|
||||
import matter from 'gray-matter'
|
||||
|
||||
import { updateContentDirectory } from '../lib/update-markdown.js'
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
import nock from 'nock'
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { getChangelogItems } from '#src/changelogs/lib/changelog.js'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, test } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import {
|
||||
getComponentTheme,
|
||||
getCssTheme,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
import walk from 'walk-sync'
|
||||
import { zip, difference } from 'lodash-es'
|
||||
import GithubSlugger from 'github-slugger'
|
||||
import { decode } from 'html-entities'
|
||||
import { beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import matter from '#src/frame/lib/read-frontmatter.js'
|
||||
import { renderContent } from '#src/content-render/index.js'
|
||||
@@ -33,10 +35,13 @@ describe('category pages', () => {
|
||||
const productIndices = walk(contentDir, walkOptions)
|
||||
const productNames = productIndices.map((index) => path.basename(path.dirname(index)))
|
||||
|
||||
// Combine those to fit Jest's `.each` usage
|
||||
// Combine those to fit vitest's `.each` usage
|
||||
const productTuples = zip(productNames, productIndices)
|
||||
|
||||
describe.each(productTuples)('product "%s"', (productName, productIndex) => {
|
||||
// Use a regular forEach loop to generate the `describe(...)` blocks
|
||||
// otherwise, if one of them has no categories, the tests will fail.
|
||||
productTuples.forEach((tuple) => {
|
||||
const [, productIndex] = tuple
|
||||
// Get links included in product index page.
|
||||
// Each link corresponds to a product subdirectory (category).
|
||||
// Example: "getting-started-with-github"
|
||||
@@ -48,7 +53,7 @@ describe('category pages', () => {
|
||||
const categoryLinks = data.children
|
||||
// Only include category directories, not standalone category files like content/actions/quickstart.md
|
||||
.filter((link) => fs.existsSync(getPath(productDir, link, 'index')))
|
||||
// TODO this should move to async, but you can't asynchronously define tests with Jest...
|
||||
// TODO this should move to async, but you can't asynchronously define tests with vitest...
|
||||
|
||||
// Map those to the Markdown file paths that represent that category page index
|
||||
const categoryPaths = categoryLinks.map((link) => getPath(productDir, link, 'index'))
|
||||
@@ -56,11 +61,9 @@ describe('category pages', () => {
|
||||
// Make them relative for nicer display in test names
|
||||
const categoryRelativePaths = categoryPaths.map((p) => path.relative(contentDir, p))
|
||||
|
||||
// Combine those to fit Jest's `.each` usage
|
||||
// Combine those to fit vitests's `.each` usage
|
||||
const categoryTuples = zip(categoryRelativePaths, categoryPaths, categoryLinks)
|
||||
|
||||
if (!categoryTuples.length) return
|
||||
|
||||
describe.each(categoryTuples)(
|
||||
'category index "%s"',
|
||||
(indexRelPath, indexAbsPath, indexLink) => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import yaml from 'js-yaml'
|
||||
import { readFile } from 'fs/promises'
|
||||
|
||||
import walk from 'walk-sync'
|
||||
import { beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { liquid } from '#src/content-render/index.js'
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
import yaml from 'js-yaml'
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import slash from 'slash'
|
||||
import walk from 'walk-sync'
|
||||
import { zip } from 'lodash-es'
|
||||
import yaml from 'js-yaml'
|
||||
import fs from 'fs/promises'
|
||||
import { beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import languages from '#src/languages/lib/languages.js'
|
||||
import { getDiffFiles } from '../lib/diff-files.js'
|
||||
@@ -235,198 +237,198 @@ if (ymlToLint.length === 0) {
|
||||
describe('deliberately do nothing', () => {
|
||||
test('void', () => {})
|
||||
})
|
||||
}
|
||||
} else {
|
||||
describe('lint yaml content', () => {
|
||||
if (ymlToLint.length < 1) return
|
||||
describe.each(ymlToLint)('%s', (yamlRelPath, yamlAbsPath) => {
|
||||
let dictionary, isEarlyAccess, fileContents
|
||||
// This variable is used to determine if the file was parsed successfully.
|
||||
// When `yaml.load()` fails to parse the file, it is overwritten with the error message.
|
||||
// `false` is intentionally chosen since `null` and `undefined` are valid return values.
|
||||
let dictionaryError = false
|
||||
|
||||
describe('lint yaml content', () => {
|
||||
if (ymlToLint.length < 1) return
|
||||
describe.each(ymlToLint)('%s', (yamlRelPath, yamlAbsPath) => {
|
||||
let dictionary, isEarlyAccess, fileContents
|
||||
// This variable is used to determine if the file was parsed successfully.
|
||||
// When `yaml.load()` fails to parse the file, it is overwritten with the error message.
|
||||
// `false` is intentionally chosen since `null` and `undefined` are valid return values.
|
||||
let dictionaryError = false
|
||||
beforeAll(async () => {
|
||||
fileContents = await fs.readFile(yamlAbsPath, 'utf8')
|
||||
try {
|
||||
dictionary = yaml.load(fileContents, { filename: yamlRelPath })
|
||||
} catch (error) {
|
||||
dictionaryError = error
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
fileContents = await fs.readFile(yamlAbsPath, 'utf8')
|
||||
try {
|
||||
dictionary = yaml.load(fileContents, { filename: yamlRelPath })
|
||||
} catch (error) {
|
||||
dictionaryError = error
|
||||
}
|
||||
isEarlyAccess = yamlRelPath.split('/').includes('early-access')
|
||||
})
|
||||
|
||||
isEarlyAccess = yamlRelPath.split('/').includes('early-access')
|
||||
})
|
||||
test('it can be parsed as a single yaml document', () => {
|
||||
expect(dictionaryError).toBe(false)
|
||||
})
|
||||
|
||||
test('it can be parsed as a single yaml document', () => {
|
||||
expect(dictionaryError).toBe(false)
|
||||
})
|
||||
|
||||
test('placeholder string is not present in any yaml files', () => {
|
||||
const matches = fileContents.match(placeholderRegex) || []
|
||||
const errorMessage = `
|
||||
test('placeholder string is not present in any yaml files', () => {
|
||||
const matches = fileContents.match(placeholderRegex) || []
|
||||
const errorMessage = `
|
||||
Found ${matches.length} placeholder string '${placeholder}'! Please update all placeholders.
|
||||
`
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('relative URLs must start with "/"', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(relativeArticleLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(relativeArticleLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('must not leak Early Access doc URLs', async () => {
|
||||
// Only execute for docs that are NOT Early Access
|
||||
if (!isEarlyAccess) {
|
||||
test('relative URLs must start with "/"', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(earlyAccessLinkRegex) || []
|
||||
const valMatches = contentStr.match(relativeArticleLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(earlyAccessLinkErrorText, matches)
|
||||
const errorMessage = formatLinkError(relativeArticleLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('must not leak Early Access image URLs', async () => {
|
||||
// Only execute for docs that are NOT Early Access
|
||||
if (!isEarlyAccess) {
|
||||
test('must not leak Early Access doc URLs', async () => {
|
||||
// Only execute for docs that are NOT Early Access
|
||||
if (!isEarlyAccess) {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(earlyAccessLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(earlyAccessLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
}
|
||||
})
|
||||
|
||||
test('must not leak Early Access image URLs', async () => {
|
||||
// Only execute for docs that are NOT Early Access
|
||||
if (!isEarlyAccess) {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(earlyAccessImageRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(earlyAccessImageErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
}
|
||||
})
|
||||
|
||||
test('must have correctly formatted Early Access image URLs', async () => {
|
||||
// Execute for ALL docs (not just Early Access) to ensure non-EA docs
|
||||
// are not leaking incorrectly formatted EA image URLs
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(earlyAccessImageRegex) || []
|
||||
const valMatches = contentStr.match(badEarlyAccessImageRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(earlyAccessImageErrorText, matches)
|
||||
const errorMessage = formatLinkError(badEarlyAccessImageErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('must have correctly formatted Early Access image URLs', async () => {
|
||||
// Execute for ALL docs (not just Early Access) to ensure non-EA docs
|
||||
// are not leaking incorrectly formatted EA image URLs
|
||||
const matches = []
|
||||
test('URLs must not contain a hard-coded language code', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(badEarlyAccessImageRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(languageLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(badEarlyAccessImageErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
const errorMessage = formatLinkError(languageLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('URLs must not contain a hard-coded language code', async () => {
|
||||
const matches = []
|
||||
test('URLs must not contain a hard-coded version number', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(languageLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(versionLinkRegEx) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(languageLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
const errorMessage = formatLinkError(versionLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('URLs must not contain a hard-coded version number', async () => {
|
||||
const matches = []
|
||||
test('URLs must not contain a hard-coded domain name', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(versionLinkRegEx) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(domainLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(versionLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
const errorMessage = formatLinkError(domainLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('URLs must not contain a hard-coded domain name', async () => {
|
||||
const matches = []
|
||||
test('does not use old site.data variable syntax', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(domainLinkRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(oldVariableRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(
|
||||
...valMatches.map((match) => {
|
||||
const example = match.replace(
|
||||
/{{\s*?site\.data\.([a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]+)+)\s*?}}/g,
|
||||
'{% data $1 %}',
|
||||
)
|
||||
return `Key "${key}": ${match} => ${example}`
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(domainLinkErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
const errorMessage = formatLinkError(oldVariableErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('does not use old site.data variable syntax', async () => {
|
||||
const matches = []
|
||||
test('does not use old octicon variable syntax', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(oldVariableRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(
|
||||
...valMatches.map((match) => {
|
||||
const example = match.replace(
|
||||
/{{\s*?site\.data\.([a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]+)+)\s*?}}/g,
|
||||
'{% data $1 %}',
|
||||
)
|
||||
return `Key "${key}": ${match} => ${example}`
|
||||
}),
|
||||
)
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(oldOcticonRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(oldVariableErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
|
||||
test('does not use old octicon variable syntax', async () => {
|
||||
const matches = []
|
||||
|
||||
for (const [key, content] of Object.entries(dictionary)) {
|
||||
const contentStr = getContent(content)
|
||||
if (!contentStr) continue
|
||||
const valMatches = contentStr.match(oldOcticonRegex) || []
|
||||
if (valMatches.length > 0) {
|
||||
matches.push(...valMatches.map((match) => `Key "${key}": ${match}`))
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = formatLinkError(oldOcticonErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
const errorMessage = formatLinkError(oldOcticonErrorText, matches)
|
||||
expect(matches.length, errorMessage).toBe(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { loadPages, loadPageMap } from '#src/frame/lib/page-data.js'
|
||||
import loadRedirects from '#src/redirects/lib/precompile.js'
|
||||
import { checkURL } from '#src/tests/helpers/check-url.js'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path'
|
||||
import { isEqual, uniqWith } from 'lodash-es'
|
||||
import { jest } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import patterns from '#src/frame/lib/patterns.js'
|
||||
import { getDataByLanguage, getDeepDataByLanguage } from '#src/data-directory/lib/get-data.js'
|
||||
@@ -30,7 +30,7 @@ const getDataReferences = (content) => {
|
||||
}
|
||||
|
||||
describe('data references', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('every data reference found in English variable files is defined and has a value', async () => {
|
||||
let errors = []
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { codeAnnotations } from '../../lib/linting-rules/code-annotations.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { codeFenceLineLength } from '../../lib/linting-rules/code-fence-line-length.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import {
|
||||
earlyAccessReferences,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import {
|
||||
expiredContent,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { frontmatterHiddenDocs } from '../../lib/linting-rules/frontmatter-hidden-docs.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { frontmatterSchema } from '../../lib/linting-rules/frontmatter-schema.js'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { frontmatterVideoTranscripts } from '../../lib/linting-rules/frontmatter-video-transcripts.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { githubOwnedActionReferences } from '../../lib/linting-rules/github-owned-action-references.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { hardcodedDataVariable } from '../../lib/linting-rules/hardcoded-data-variable.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { imageAltTextEndPunctuation } from '../../lib/linting-rules/image-alt-text-end-punctuation.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { imageAltTextExcludeStartWords } from '../../lib/linting-rules/image-alt-text-exclude-start-words.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { incorrectAltTextLength } from '../../lib/linting-rules/image-alt-text-length.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { imageFileKebabCase } from '../../lib/linting-rules/image-file-kebab-case.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { imageNoGif } from '../../lib/linting-rules/image-no-gif.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { internalLinksNoLang } from '../../lib/linting-rules/internal-links-no-lang.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { internalLinksOldVersion } from '../../lib/linting-rules/internal-links-old-version.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { internalLinksSlash } from '../../lib/linting-rules/internal-links-slash.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { linkPunctuation } from '../../lib/linting-rules/link-punctuation.js'
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import path from 'path'
|
||||
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import {
|
||||
liquidDataReferencesDefined,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import {
|
||||
liquidIfVersionVersions,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { liquidQuotedConditionalArg } from '../../lib/linting-rules/liquid-quoted-conditional-arg.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { frontmatterLiquidSyntax, liquidSyntax } from '../../lib/linting-rules/liquid-syntax.js'
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import path from 'path'
|
||||
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { liquidIfTags, liquidIfVersionTags } from '../../lib/linting-rules/liquid-versioning.js'
|
||||
import { nextNext } from '#src/versions/lib/enterprise-server-releases.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { listFirstWordCapitalization } from '../../lib/linting-rules/list-first-word-capitalization.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { raiReusableUsage } from '../../lib/linting-rules/rai-reusable-usage.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import searchReplace from 'markdownlint-rule-search-replace'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { runRule } from '../../lib/init-test.js'
|
||||
import { yamlScheduledJobs } from '../../lib/linting-rules/yaml-scheduled-jobs.js'
|
||||
|
||||
|
||||
@@ -1,4 +1,27 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`annotate > renders annotations 1`] = `
|
||||
"<div class="annotate beside"><div class="annotate-header"><header class="d-flex flex-items-center flex-justify-between p-2 text-small rounded-top-1 border-top border-left border-right"><span class="flex-1">YAML</span><div class="BtnGroup"><button name="annotate-display" value="beside" type="button" class="BtnGroup-item btn btn-sm">Beside</button><button name="annotate-display" value="inline" type="button" class="BtnGroup-item btn btn-sm">Inline</button></div><button class="js-btn-copy btn btn-sm tooltipped tooltipped-nw" aria-label="Copy YAML code to clipboard" data-clipboard="1746955726" aria-live="polite" aria-atomic="true"><svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-copy" aria-hidden="true"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><pre hidden data-clipboard="1746955726"># The name of the workflow as it will appear in the "Actions" tab of the GitHub repository.
|
||||
name: Post welcome comment
|
||||
|
||||
# Add the \`pull_request\` event, so that the workflow runs automatically
|
||||
# every time a pull request is created.
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
</pre></header></div><div class="annotate-beside"><div class="annotate-row"><div class="annotate-code"><pre><code class="hljs language-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Post</span> <span class="hljs-string">welcome</span> <span class="hljs-string">comment</span></code></pre></div><div class="annotate-note"><p>The name of the workflow as it will appear in the "Actions" tab of the GitHub repository.</p></div></div><div class="annotate-row"><div class="annotate-code"><pre><code class="hljs language-yaml"><span class="hljs-attr">on:</span>
|
||||
<span class="hljs-attr">pull_request:</span>
|
||||
<span class="hljs-attr">types:</span> [<span class="hljs-string">opened</span>]</code></pre></div><div class="annotate-note"><p>Add the <code>pull_request</code> event, so that the workflow runs automatically
|
||||
every time a pull request is created.</p></div></div></div><div class="annotate-inline"><pre><code class="hljs language-yaml"><span class="hljs-comment"># The name of the workflow as it will appear in the "Actions" tab of the GitHub repository.</span>
|
||||
<span class="hljs-attr">name:</span> <span class="hljs-string">Post</span> <span class="hljs-string">welcome</span> <span class="hljs-string">comment</span>
|
||||
|
||||
<span class="hljs-comment"># Add the \`pull_request\` event, so that the workflow runs automatically</span>
|
||||
<span class="hljs-comment"># every time a pull request is created.</span>
|
||||
<span class="hljs-attr">on:</span>
|
||||
<span class="hljs-attr">pull_request:</span>
|
||||
<span class="hljs-attr">types:</span> [<span class="hljs-string">opened</span>]
|
||||
</code></pre></div></div>"
|
||||
`;
|
||||
|
||||
exports[`annotate renders annotations 1`] = `
|
||||
"<div class="annotate beside"><div class="annotate-header"><header class="d-flex flex-items-center flex-justify-between p-2 text-small rounded-top-1 border-top border-left border-right"><span class="flex-1">YAML</span><div class="BtnGroup"><button name="annotate-display" value="beside" type="button" class="BtnGroup-item btn btn-sm">Beside</button><button name="annotate-display" value="inline" type="button" class="BtnGroup-item btn btn-sm">Inline</button></div><button class="js-btn-copy btn btn-sm tooltipped tooltipped-nw" aria-label="Copy YAML code to clipboard" data-clipboard="1746955726" aria-live="polite" aria-atomic="true"><svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-copy" aria-hidden="true"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><pre hidden data-clipboard="1746955726"># The name of the workflow as it will appear in the "Actions" tab of the GitHub repository.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import cheerio from 'cheerio'
|
||||
|
||||
import { renderContent } from '#src/content-render/index.js'
|
||||
|
||||
const example = `
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterAll, beforeAll, expect, describe } from '@jest/globals'
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import Page from '#src/frame/lib/page.js'
|
||||
import languages from '#src/languages/lib/languages.js'
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { afterAll, jest, beforeAll, expect } from '@jest/globals'
|
||||
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { liquid } from '#src/content-render/index.js'
|
||||
import languages from '#src/languages/lib/languages.js'
|
||||
import { DataDirectory } from '#src/tests/helpers/data-directory.js'
|
||||
|
||||
describe('liquid helper tags', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
const context = {}
|
||||
let dd
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { jest } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { liquid } from '#src/content-render/index.js'
|
||||
import shortVersionsMiddleware from '#src/versions/middleware/short-versions.js'
|
||||
@@ -43,7 +43,7 @@ const contextualize = (req) => {
|
||||
}
|
||||
|
||||
describe('liquid template parser', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
describe('short versions', () => {
|
||||
// Create a fake req so we can test the shortVersions middleware
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { renderContent } from '#src/content-render/index.js'
|
||||
|
||||
describe('octicon tag', () => {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
import path from 'path'
|
||||
|
||||
import { jest } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { head, get } from '#src/tests/helpers/e2etest.js'
|
||||
import { loadPages } from '#src/frame/lib/page-data.js'
|
||||
@@ -62,7 +62,7 @@ function getContentFiles(spaceSeparatedList) {
|
||||
// It can also happen if some of the pages involves are infamously slow.
|
||||
// For example guide pages because they involved a lot of processing
|
||||
// to gather and preview linked data.
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
describe('changed-content', () => {
|
||||
const changedContentFiles = getChangedContentFiles()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import cheerio from 'cheerio'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { renderContent } from '#src/content-render/index.js'
|
||||
import { EOL } from 'os'
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { beforeAll } from '@jest/globals'
|
||||
import yaml from 'js-yaml'
|
||||
import { readFileSync } from 'fs'
|
||||
import walk from 'walk-sync'
|
||||
import { extname, basename } from 'path'
|
||||
|
||||
import walk from 'walk-sync'
|
||||
import { beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { getJsonValidator, validateJson } from '#src/tests/lib/validate-json-schema.js'
|
||||
import { formatAjvErrors } from '#src/tests/helpers/schemas.js'
|
||||
import dataSchemas from '#src/data-directory/lib/data-schemas/index.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import filenameToKey from '#src/data-directory/lib/filename-to-key.js'
|
||||
|
||||
describe('filename-to-key', () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import { expect, test, describe, beforeAll, afterAll } from '@jest/globals'
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import languages from '#src/languages/lib/languages.js'
|
||||
import {
|
||||
@@ -14,7 +14,7 @@ import { DataDirectory } from '#src/tests/helpers/data-directory.js'
|
||||
describe('get-data', () => {
|
||||
let dd
|
||||
const enDirBefore = languages.en.dir
|
||||
// Only `en` is available in jest tests, so pretend we also have Japanese
|
||||
// Only `en` is available in tests, so pretend we also have Japanese
|
||||
languages.ja = Object.assign({}, languages.en, {})
|
||||
|
||||
beforeAll(() => {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import dataDirectory from '#src/data-directory/lib/data-directory.js'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const fixturesDir = path.join(__dirname, 'fixtures')
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { stat } from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect } from 'vitest'
|
||||
|
||||
import { testViaActionsOnly } from '#src/tests/helpers/conditional-runs.js'
|
||||
import { get, getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, jest, test } from '@jest/globals'
|
||||
import { expect, test, vi } from 'vitest'
|
||||
import { get, getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
import { describeIfDocsEarlyAccess } from '#src/tests/helpers/conditional-runs.js'
|
||||
@@ -7,7 +7,7 @@ import languages from '#src/languages/lib/languages.js'
|
||||
const VALID_EARLY_ACCESS_URI = '/early-access/github/save-time-with-slash-commands'
|
||||
|
||||
describeIfDocsEarlyAccess('early access rendering', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('viewing landing page', async () => {
|
||||
const res = await get('/en/early-access')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { afterEach } from '@jest/globals'
|
||||
import { afterEach, describe, expect, test } from 'vitest'
|
||||
|
||||
import nock from 'nock'
|
||||
import { publish } from '../lib/hydro.js'
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { validateJson } from '#src/tests/lib/validate-json-schema.js'
|
||||
import { formatErrors } from '../lib/middleware-errors.js'
|
||||
import { schemas } from '../lib/schema.js'
|
||||
|
||||
expect.extend({
|
||||
toMatchSchema(data, schema) {
|
||||
const { isValid, errors } = validateJson(schema, data)
|
||||
return {
|
||||
pass: isValid,
|
||||
message: () => (isValid ? '' : errors.message),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
describe('formatErrors', () => {
|
||||
test('should produce objects that match the validation spec', () => {
|
||||
expect.extend({
|
||||
toMatchSchema(data, schema) {
|
||||
const { isValid, errors } = validateJson(schema, data)
|
||||
return {
|
||||
pass: isValid,
|
||||
message: () => (isValid ? '' : errors.message),
|
||||
}
|
||||
},
|
||||
})
|
||||
// Produce an error
|
||||
const { errors } = validateJson({ type: 'string' }, 0)
|
||||
const formattedErrors = formatErrors(errors, '')
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { expect, jest } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { post } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('POST /events', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
async function checkEvent(data) {
|
||||
const body = JSON.stringify(data)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { parseUserAgent } from '../components/user-agent.ts'
|
||||
|
||||
describe('parseUserAgent', () => {
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
There are currently 3 general automated tests:
|
||||
|
||||
1. `jest` tests against real English content (and some code)
|
||||
1. `jest` tests against fixture content
|
||||
1. `vitest` tests against real English content (and some code)
|
||||
1. `vitest` tests against fixture content
|
||||
1. `playwright` tests against fixture content (What this document is about!)
|
||||
|
||||
## Quickstart
|
||||
|
||||
Just like with regular `jest` tests, if you haven't already done so...
|
||||
Just like with regular `vitest` tests, if you haven't already done so...
|
||||
|
||||
```shell
|
||||
npm run build
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('annotations', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { head } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('bad URLs', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('breadcrumbs', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM, head } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('map topics', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
import nonEnterpriseDefaultVersion from '#src/versions/lib/non-enterprise-default-version.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOMCached as getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('glossary', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { get, getDOMCached as getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('guides', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('<head>', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { get, getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import { get, head, getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { get, getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
import enterpriseServerReleases from '#src/versions/lib/enterprise-server-releases.js'
|
||||
import { allVersions } from '#src/versions/lib/all-versions.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('product landing page', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDataByLanguage } from '#src/data-directory/lib/get-data.js'
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
import { supported } from '#src/versions/lib/enterprise-server-releases.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('markdown rendering', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import enterpriseServerReleases from '#src/versions/lib/enterprise-server-releases.js'
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('permission statements', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOMCached as getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('sidebar', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { TRANSLATIONS_FIXTURE_ROOT } from '#src/frame/lib/constants.js'
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM, head } from '#src/tests/helpers/e2etest.js'
|
||||
import { supported } from '#src/versions/lib/enterprise-server-releases.js'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { expect, jest, test } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { get } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('general /api pages', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test("any /api URL that isn't found should JSON", async () => {
|
||||
const res = await get('/api')
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { blockIndex } from '#src/frame/middleware/block-robots.js'
|
||||
import { productMap } from '#src/products/lib/all-products.js'
|
||||
import enterpriseServerReleases from '#src/versions/lib/enterprise-server-releases.js'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from 'path'
|
||||
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import walk from 'walk-sync'
|
||||
|
||||
import createTree from '#src/frame/lib/create-tree.js'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { expect, jest } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { SURROGATE_ENUMS } from '#src/frame/middleware/set-fastly-surrogate-key.js'
|
||||
import { get } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('favicon assets', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('should serve a valid and aggressively caching /favicon.ico', async () => {
|
||||
const res = await get('/favicon.ico')
|
||||
|
||||
@@ -2,7 +2,7 @@ import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
import http from 'http'
|
||||
|
||||
import { expect, describe, test } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import Page from '#src/frame/lib/page.js'
|
||||
import findPage from '#src/frame/middleware/find-page.js'
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { jest } from '@jest/globals'
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import Page from '#src/frame/lib/page.js'
|
||||
import findPage from '#src/frame/lib/find-page.js'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
describe('find page', () => {
|
||||
jest.setTimeout(1000 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('follows redirects', async () => {
|
||||
const page = await Page.init({
|
||||
|
||||
@@ -3,8 +3,9 @@ import path from 'path'
|
||||
import os from 'os'
|
||||
|
||||
import { rimraf } from 'rimraf'
|
||||
import { expect, test, describe, beforeAll, afterAll } from '@jest/globals'
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest'
|
||||
import nock from 'nock'
|
||||
|
||||
import getRemoteJSON, { cache } from '#src/frame/lib/get-remote-json.js'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
const gitignorePath = path.join(process.cwd(), '.gitignore')
|
||||
const gitignore = await fs.readFile(gitignorePath, 'utf8')
|
||||
const entries = gitignore.split(/\r?\n/)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import { SURROGATE_ENUMS } from '#src/frame/middleware/set-fastly-surrogate-key.js'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect } from '@jest/globals'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import getMiniTocItems from '#src/frame/lib/get-mini-toc-items'
|
||||
|
||||
function generateHeading(h) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { describe, expect, jest, test } from '@jest/globals'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { get } from '#src/tests/helpers/e2etest.js'
|
||||
|
||||
describe('bad requests', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
vi.setConfig({ testTimeout: 60 * 1000 })
|
||||
|
||||
test('any _next/image request should 404', async () => {
|
||||
const res = await get('/_next/image?what=ever')
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import path from 'path'
|
||||
|
||||
import cheerio from 'cheerio'
|
||||
import { describe, expect } from '@jest/globals'
|
||||
import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
|
||||
|
||||
import Page, { FrontmatterErrorsError } from '#src/frame/lib/page.js'
|
||||
import { allVersions } from '#src/versions/lib/all-versions.js'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user