test_lib_test_browsers_test.js
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict'
const assert = require('node:assert')
const fs = require('node:fs')
const path = require('node:path')
// The browsers with Bazel test targets: the keys of BROWSERS in javascript/private/browsers.bzl.
const BAZEL_BROWSERS = ['chrome', 'edge', 'firefox']
const BROWSER_NAMES = {
'Browser.CHROME': 'chrome',
"'chrome'": 'chrome',
'Browser.EDGE': 'edge',
"'MicrosoftEdge'": 'edge',
'Browser.FIREFOX': 'firefox',
"'firefox'": 'firefox',
'Browser.SAFARI': 'safari',
"'safari'": 'safari',
'Browser.INTERNET_EXPLORER': 'internet explorer',
"'internet explorer'": 'internet explorer',
}
function testFiles(dir) {
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const file = path.join(dir, entry.name)
if (entry.isDirectory()) return testFiles(file)
return entry.name.endsWith('_test.js') ? [file] : []
})
}
/** The Bazel browsers a file's suite() calls run against, or null when it calls no suite(). */
function suiteBrowsers(file) {
const source = fs.readFileSync(file, 'utf8')
const suites = source.match(/\bsuite\(/g)?.length ?? 0
if (suites === 0) return null
const options = [...source.matchAll(/browsers:\s*\[([^\]]*)\]/g)].map((m) => m[1])
if (options.length < suites) return BAZEL_BROWSERS
const names = new Set()
for (const option of options) {
for (const token of option.split(',').map((t) => t.trim())) {
if (!token) continue
assert.ok(token in BROWSER_NAMES, `${file}: unrecognized browser ${token} in a suite's browsers option`)
names.add(BROWSER_NAMES[token])
}
}
return BAZEL_BROWSERS.filter((browser) => names.has(browser))
}
function readTestBrowsers() {
const source = fs.readFileSync('test/test_browsers.bzl', 'utf8')
const map = new Map()
for (const [, file, list] of source.matchAll(/"(test\/[^"]+)":\s*\[([^\]]*)\]/g)) {
map.set(
file,
[...list.matchAll(/"([^"]+)"/g)].map((m) => m[1]),
)
}
return map
}
describe('test/test_browsers.bzl', function () {
const testBrowsers = readTestBrowsers()
it('matches the browsers each test file limits its suite() to', function () {
const mismatches = []
for (const file of testFiles('test')) {
const browsers = suiteBrowsers(file)
if (browsers === null) continue
const all = browsers.length === BAZEL_BROWSERS.length
const listed = testBrowsers.get(file)
if (all && listed !== undefined) {
mismatches.push(`${file} runs on every browser; remove its entry`)
} else if (!all && JSON.stringify(listed) !== JSON.stringify(browsers)) {
mismatches.push(`${file} should be "${file}": ${JSON.stringify(browsers)}`)
}
}
assert.deepStrictEqual(mismatches, [])
})
it('lists only test files that exist', function () {
const missing = [...testBrowsers.keys()].filter((file) => !fs.existsSync(file))
assert.deepStrictEqual(missing, [])
})
})