Best JavaScript code snippet using wpt
run-wpt.mjs
Source:run-wpt.mjs
1import { stdin, stdout, stderr } from "process";2import { argv } from 'process';3import { execFile } from "child_process";4import { on, once } from "events";5import { existsSync, mkdirSync, rmSync, readFileSync, writeFileSync, stat } from "fs";6import http from "http";7import path from "path";8let LogLevel = {9 Quiet: 0,10 Verbose: 1,11 VeryVerbose: 2,12};13function relativePath(path) {14 return new URL(path, import.meta.url).pathname;15}16const SLOW_PREFIX = "SLOW ";17const config = {18 viceroy: {19 external: false,20 configFile: relativePath("./viceroy.toml"),21 host: "http://localhost:7878",22 runtime: "wpt-runtime.wasm",23 },24 wptServer: {25 external: false,26 path: relativePath("./wpt/wpt"),27 },28 server: {29 port: 7879,30 },31 tests: {32 list: relativePath("tests.json"),33 expectations: relativePath("expectations"),34 updateExpectations: false,35 pattern: "",36 },37 results: {38 pageTemplate: relativePath("results-page.template.html"),39 sectionTemplate: relativePath("results-section.template.html"),40 sectionErrorTemplate: relativePath("results-section-error.template.html"),41 },42 interactive: false,43 skipSlowTests: false,44 logLevel: LogLevel.Quiet,45};46const ArgParsers = {47 "--runtime": {48 help: `Path to .wasm file containing the WPT tests runtime to use (default: ${config.viceroy.runtime})`,49 cmd: val => { config.viceroy.runtime = val }50 },51 "--port": {52 help: `Port to run the server on in interactive mode (default: ${config.server.port})`,53 cmd: val => {54 config.server.port = parseInt(val, 10);55 if (isNaN(config.server.port)) {56 return `Invalid value for --port: ${val}`;57 }58 }59 },60 "--external-viceroy": {61 help: "Don't start a Viceroy instance internally (default: false)",62 cmd: () => { config.viceroy.external = true; }63 },64 "--external-wpt-server": {65 help: "Don't start an instance of the WPT server internally (default: false)",66 cmd: () => { config.wptServer.external = true; }67 },68 "--expectations": {69 help: `Path to the directory containing test expectations files (default: ${config.tests.expectations}}`,70 cmd: val => { config.tests.expectations = val; }71 },72 "--update-expectations": {73 help: "Update test expectations file with results from the current run (default: false)",74 cmd: () => { config.tests.updateExpectations = true; }75 },76 "--interactive": {77 help: "Start a server instead of directly running tests",78 cmd: () => { config.interactive = true; }79 },80 "--skip-slow-tests": {81 help: "Skip tests that take a long time, in particular in debug builds of the runtime",82 cmd: () => { config.skipSlowTests = true; }83 },84 "-v": {85 help: "Verbose output",86 cmd: () => { config.logLevel = LogLevel.Verbose; }87 },88 "-vv": {89 help: "Very verbose output",90 cmd: () => { config.logLevel = LogLevel.VeryVerbose; }91 },92 "--help": {93 help: "Print this help message",94 cmd: () => {95 console.log(`Usage:96 node run-wpt.mjs [...options] [pattern]97If a pattern is provided, only tests whose path contains the pattern will be run98Options:`);99 for (let [name, parser] of Object.entries(ArgParsers)) {100 console.log(` ${(name + (parser.cmd.length > 0 ? "=value" : "")).padEnd(25)}${parser.help}`);101 }102 process.exit(0);103 }104 },105}106function applyConfig(argv) {107 for (let entry of argv.slice(2)) {108 if (entry[0] != "-") {109 config.tests.pattern = entry;110 continue;111 }112 let [arg, val] = entry.split("=");113 let result = undefined;114 let parser = ArgParsers[arg];115 if (parser) {116 result = parser.cmd(val);117 } else {118 result = `Unknown argument: ${arg}`;119 }120 if (result) {121 console.error(result);122 process.exit(1);123 }124 }125 if (!existsSync(config.viceroy.runtime)) {126 console.error(`Runtime not found: ${config.viceroy.runtime}`);127 return false;128 }129 if (config.interactive) {130 if (config.tests.updateExpectations) {131 console.error("Can't update test expectations in interactive mode");132 return false;133 }134 }135 return true;136}137async function run() {138 if (!applyConfig(argv)) {139 return process.exit(1);140 }141 let [wptServer, viceroy] = await Promise.all([ensureWptServer(config.wptServer, config.logLevel),142 ensureViceroy(config.viceroy, config.logLevel)]);143 if (config.interactive) {144 const server = http.createServer((req, res) => handleRequest(req, res, viceroy));145 server.listen(config.server.port);146 console.log(`Listening on http://localhost:${config.server.port}`);147 } else {148 let {testPaths, totalCount } = getTests(config.tests.pattern);149 let pathLength = testPaths.reduce((length, path) => Math.max(path.length, length), 0);150 console.log(`Running ${testPaths.length} of ${totalCount} tests ...\n`);151 let expectationsUpdated = 0;152 let unexpectedFailure = false;153 let stats = await runTests(testPaths, viceroy,154 (testPath, results, stats) => {155 console.log(`${testPath.padEnd(pathLength)} ${formatStats(stats)}`);156 if (config.tests.updateExpectations && stats.unexpectedFail + stats.unexpectedPass + stats.missing > 0) {157 let expectPath = path.join(config.tests.expectations, testPath + ".json");158 console.log(`writing changed expectations to ${expectPath}`);159 let expectations = {};160 for (let result of results) {161 expectations[result.name] = {162 status: result.status === 0 ? 'PASS' : 'FAIL',163 };164 }165 mkdirSync(path.dirname(expectPath), { recursive: true });166 writeFileSync(expectPath, JSON.stringify(expectations, null, 2));167 expectationsUpdated++;168 }169 },170 (testPath, error, stats) => {171 let expectPath = path.join(config.tests.expectations, testPath + ".json");172 let exists = existsSync(expectPath);173 if (exists) {174 console.log(`UNEXPECTED ERROR: ${testPath} (${stats.duration}ms)175 MESSAGE: ${error.message}176 STACK:177 ${error.stack.split('\n').join('\n ')}`);178 if (config.tests.updateExpectations) {179 console.log(`Removing expectations file ${expectPath}`);180 rmSync(expectPath);181 expectationsUpdated++;182 } else {183 unexpectedFailure = true;184 }185 } else {186 console.log(`EXPECTED ERROR: ${testPath} (${stats.duration}ms)`);187 }188 }189 );190 console.log(`\n${"Done. Stats:".padEnd(pathLength)} ${formatStats(stats)}`);191 wptServer.process && wptServer.process.kill("SIGINT");192 viceroy.process && viceroy.process.kill("SIGINT");193 if (config.tests.updateExpectations) {194 console.log(`Expectations updated: ${expectationsUpdated}`);195 } else if (stats.unexpectedFail + stats.unexpectedPass != 0 || unexpectedFailure) {196 process.exitCode = 1;197 }198 }199}200function formatStats(stats) {201 return `${padStart(stats.pass, 4)} / ${padStart(stats.count, 4)} (${padStart("+" + stats.unexpectedPass, 5)}, ${padStart("-" + (stats.unexpectedFail), 5)}, ${padStart("?" + (stats.missing), 5)}) passing in ${padStart(stats.duration, 4)}ms`;202}203function padStart(value, length) {204 return (value + "").padStart(length);205}206async function ensureWptServer(config, logLevel) {207 if (config.external) {208 let wptServer = { ...config };209 if (logLevel > LogLevel.Quiet) {210 console.info(`Using external WPT server`);211 }212 return wptServer;213 } else {214 return await startWptServer(config.path, logLevel);215 }216}217async function startWptServer(path, logLevel) {218 if (logLevel > LogLevel.Quiet) {219 console.info(`Starting WPT server ...`);220 }221 let server = execFile(path, ["--no-h2", "serve"]);222 server.on("error", event => {223 console.error(`error starting WPT server: ${event}`);224 process.exit(1);225 });226 if (logLevel >= LogLevel.VeryVerbose) {227 server.stderr.on("data", data => {228 console.log(`WPT server stderr: ${stripTrailingNewline(data)}`);229 });230 server.stdout.on("data", data => {231 console.log(`WPT server stdout: ${stripTrailingNewline(data)}`);232 });233 }234 // Wait until the server has fully initialized.235 // `wpt.py serve` doesn't explicitly signal when it's done initializing, so we have to236 // read the tea leaves a bit, by waiting for a message that is among the very last to be237 // printed during initialization, well after the main http server has started.238 for await(let [chunk] of on(server.stdout, "data")) {239 if (/wss on port \d+\] INFO - Listen on/.test(chunk)) {240 if (logLevel > LogLevel.Quiet) {241 console.info(`Started internal WPT server`);242 }243 return { process: server, ...config };244 }245 }246}247async function ensureViceroy(config, logLevel) {248 if (config.external) {249 let viceroy = { ...config };250 if (logLevel > LogLevel.Quiet) {251 console.info(`Using external Viceroy host ${config.host}`);252 }253 return viceroy;254 } else {255 let viceroy = await startViceroy(config.runtime, config.configFile, logLevel);256 if (logLevel > LogLevel.Quiet) {257 console.info(`Started internal Viceroy host ${viceroy.host}`);258 }259 return viceroy;260 }261}262async function timeout(millis, message) {263 if (message === undefined) {264 message = `timeout reached after ${millis} milliseconds`;265 }266 return new Promise((_resolve, reject) => setTimeout(() => reject(message), millis));267}268async function viceroyReady(viceroy, config) {269 // Wait until Viceroy has fully initialized and extract host from output.270 for await(const [chunk] of on(viceroy.stdout, "data")) {271 let result = chunk.match(/INFO Listening on (.+)/);272 if (result) {273 return { process: viceroy, host: result[1], ...config };274 }275 }276}277async function startViceroy(runtime, config, logLevel) {278 if (logLevel > LogLevel.Quiet) {279 console.info(`Starting Viceroy server ...`);280 }281 let viceroy = execFile("viceroy", [runtime, "-C", config]);282 viceroy.on("error", event => {283 console.error(`error starting Viceroy: ${event}`);284 process.exit(1);285 });286 if (logLevel >= LogLevel.VeryVerbose) {287 viceroy.stderr.on("data", data => {288 console.log(`viceroy stderr: ${stripTrailingNewline(data)}`);289 });290 viceroy.stdout.on("data", data => {291 console.log(`viceroy stdout: ${stripTrailingNewline(data)}`);292 });293 }294 // give viceroy 20 seconds to become available295 const VICEROY_READY_TIMEOUT = 20000;296 return await Promise.race([297 viceroyReady(viceroy, config),298 timeout(VICEROY_READY_TIMEOUT, "Viceroy failed to start"),299 ]);300}301function stripTrailingNewline(str) {302 if (str[str.length - 1] == '\n') {303 return str.substr(0, str.length - 1);304 }305 return str;306}307function getExpectedResults(testPath) {308 testPath = path.join(config.tests.expectations, testPath + ".json");309 try {310 return JSON.parse(readFileSync(testPath));311 } catch (e) {312 if (config.tests.updateExpectations) {313 if (config.logLevel >= LogLevel.Verbose) {314 console.log(`Expectations file ${testPath} will be created with results from current run`);315 }316 }317 return {};318 }319}320function getTests(pattern) {321 config.logLevel >= LogLevel.Verbose &&322 console.log(`Loading tests list from ${config.tests.list}`);323 let testPaths = JSON.parse(readFileSync(config.tests.list, { encoding: "utf-8" }));324 let totalCount = testPaths.length;325 if (config.skipSlowTests) {326 testPaths = testPaths.filter(path => !path.startsWith(SLOW_PREFIX));327 }328 testPaths = testPaths.map(path => path.startsWith(SLOW_PREFIX) ?329 path.substr(SLOW_PREFIX.length) :330 path)331 .filter(path => path.indexOf(pattern) != -1);332 config.logLevel >= LogLevel.Verbose &&333 console.log(`Loaded ${totalCount} tests, of which ${testPaths.length} match pattern ${pattern}${config.skipSlowTests ? " and aren't skipped for being slow" : ""}`);334 return { testPaths, totalCount };335}336async function runTests(testPaths, viceroy, resultCallback, errorCallback) {337 let totalStats = {338 duration: 0,339 count: 0,340 pass: 0,341 missing: 0,342 unexpectedPass: 0,343 unexpectedFail: 0,344 };345 for (let path of testPaths) {346 if (config.logLevel >= LogLevel.Verbose) {347 console.log(`Running test ${path}`);348 }349 let expectations = getExpectedResults(path);350 let t1 = Date.now();351 let {response, body} = await request(`${viceroy.host}/${path}`);352 let stats = {353 count: 0,354 pass: 0,355 missing: 0,356 unexpectedPass: 0,357 unexpectedFail: 0,358 duration: Date.now() - t1,359 };360 totalStats.duration += stats.duration;361 let results;362 try {363 results = JSON.parse(body);364 if (response.statusCode == 500) {365 throw {message: results.error.message, stack: results.error.stack};366 }367 for (let result of results) {368 stats.count++;369 let expectation = expectations[result.name];370 if (expectation) {371 expectation.did_run = true;372 result.expected = true;373 }374 if (result.status == 0) {375 stats.pass++;376 if (!expectation || expectation.status === 'FAIL') {377 result.expected = false;378 console.log(`${expectation ? "UNEXPECTED" : "NEW"} PASS379 NAME: ${result.name}`);380 stats.unexpectedPass++;381 }382 } else if (!expectation || expectation.status === 'PASS') {383 result.expected = false;384 console.log(`${expectation ? "UNEXPECTED" : "NEW"} FAIL385 NAME: ${result.name}386 MESSAGE: ${result.message}`);387 stats.unexpectedFail++;388 }389 }390 for (let [name, expectation] of Object.entries(expectations)) {391 if (!expectation.did_run) {392 stats.missing++;393 console.log(`MISSING TEST394 NAME: ${name}395 EXPECTED RESULT: ${expectation.status}`);396 }397 }398 totalStats.count += stats.count;399 totalStats.pass += stats.pass;400 totalStats.missing += stats.missing;401 totalStats.unexpectedPass += stats.unexpectedPass;402 totalStats.unexpectedFail += stats.unexpectedFail;403 await resultCallback(path, results, stats);404 } catch (e) {405 if (!results) {406 e = new Error(`Parsing test results as JSON failed. Output was:\n ${body}`);407 }408 if (config.logLevel >= LogLevel.Verbose) {409 console.log(`Error running file ${path}: ${e.message}, stack:\n${e.stack}`);410 }411 await errorCallback(path, e, stats);412 }413 }414 return totalStats;415}416async function handleRequest(req, res, viceroy) {417 let pattern = req.url.substr(1);418 if (pattern == "favicon.ico") {419 return;420 }421 let {testPaths, totalCount } = getTests(pattern);422 res.writeHead(200, { 'Content-Type': 'text/html' });423 let page = readFileSync(config.results.pageTemplate, { encoding: "utf-8" });424 let [pageStart, pageEnd] = page.split("{results}");425 pageStart = pageStart.split("{pattern}").join(`${pattern}`);426 pageStart = pageStart.split("{count}").join(`${testPaths.length} of ${totalCount}`);427 res.write(pageStart);428 let section = readFileSync(config.results.sectionTemplate, { encoding: "utf-8" });429 let template = new Function("prefix", "title", "info", "pass", "total", "duration", "rows", `return \`${section}\``);430 let section_error = readFileSync(config.results.sectionErrorTemplate, { encoding: "utf-8" });431 let error_template = new Function("prefix", "title", "message", "stack", `return \`${section_error}\``);432 let { duration, pass, count } = await runTests(testPaths, viceroy,433 (testPath, results, stats) => {434 let table = renderResultsTable(testPath, results, stats, template);435 res.write(table);436 },437 (testPath, error, stats) => {438 let expectPath = path.join(config.tests.expectations, testPath + ".json");439 let exists = existsSync(expectPath);440 let table = error_template(`${exists ? "UN" : ""}EXPECTED ERROR: `, testPath, error.message,441 renderStack(error.stack));442 res.write(table);443 }444 );445 res.end(pageEnd.split("{pass}").join(pass).split("{total}").join(count).split("{duration}").join(duration));446}447async function request(url) {448 return new Promise(async (resolve, reject) => {449 let request = http.get(url);450 let [response] = await once(request, "response");451 response.setEncoding('utf8');452 let body = "";453 response.on("data", chunk => { body += chunk; });454 await once(response, "end");455 resolve({ response, body });456 });457}458function renderResultsTable(title, results, stats, template) {459 let rows = results.map(test => {460 let name = test.name.split("<").join("<").split(">").join(">");461 return `<tr class="result ${test.status == 0 ? "pass" : "fail"}${test.expected ? " expected" : ""}">462 <td class="name">${name}</td>463 <td class="grade">${test.status == 0 ? "PASS" : "FAIL"}</td>464 <td message>${465 test.status ?466 `<p>${test.message}</p>467 <details>468 <summary>Stack</summary>469 ${renderStack(test.stack)}470 </details>`471 : ""472 }</td>473 `474 }475 ).join("\n");476 return template("", title, "", stats.pass, stats.count, stats.duration, rows);477}478function renderStack(stack) {479 stack = stack.split("<").join("<");480 stack = stack.split(">").join(">");481 // Strip the parts of the stack that's just about handling asserts.482 let lines = stack.split("\n");483 for (let i = 0; i < lines.length; i++) {484 if (lines[i].indexOf("assert_wrapper") > -1) {485 lines = lines.slice(i + 1);486 break;487 }488 }489 stack = lines.join("<br>");490 return stack;491}...
app_data.spec.ts
Source:app_data.spec.ts
1import { expect } from "chai";2import {3 AppData,4 serializeAppData,5 deserializeAppData,6 createAppData,7 addTag,8 deleteTag,9 updateTag,10 applyTagToBook,11 applyTagToUser,12 removeTagFromBook,13 removeTagFromUser14} from "./app_data";15import { assertWrapper } from "../assert_wrapper";16describe("AppData", function() {17 describe("addTag", function() {18 it("Simple", function() {19 const appData = createAppData({20 tags: [21 {22 id: 3,23 name: "original"24 }25 ]26 });27 assertWrapper(appData);28 const [actual] = addTag(appData, "new");29 const expected = createAppData({30 tags: [31 {32 id: 3,33 name: "original"34 },35 {36 id: 4,37 name: "new"38 }39 ]40 });41 expect(actual).deep.equals(expected);42 });43 });44 describe("deleteTag", function() {45 it("Simple", function() {46 const appData = createAppData({47 tags: [48 {49 id: 3,50 name: "simple"51 }52 ]53 });54 assertWrapper(appData);55 const actual = deleteTag(appData, 3);56 const expected = [createAppData(), true];57 expect(actual).deep.equals(expected);58 });59 it("Fail", function() {60 const appData = createAppData({61 tags: [62 {63 id: 3,64 name: "noble"65 }66 ]67 });68 assertWrapper(appData);69 const actual = deleteTag(appData, 30);70 const expected = [appData, false];71 expect(actual).deep.equals(expected);72 });73 it("Cascade", function() {74 const appData = createAppData({75 books: [76 {77 id: 2938,78 title: "True Love",79 author: "Con"80 }81 ],82 users: [83 {84 id: 3452,85 firstName: "Dominic",86 lastName: "Sawyer"87 }88 ],89 tags: [90 {91 id: 192,92 name: "remaining"93 },94 {95 id: 121,96 name: "vanishing"97 }98 ],99 bookTags: [[2938, [192, 121]]],100 userTags: [[3452, [121, 192]]]101 });102 assertWrapper(appData);103 const actual = deleteTag(appData, 121);104 const expected = [105 createAppData({106 books: [107 {108 id: 2938,109 title: "True Love",110 author: "Con"111 }112 ],113 users: [114 {115 id: 3452,116 firstName: "Dominic",117 lastName: "Sawyer"118 }119 ],120 tags: [121 {122 id: 192,123 name: "remaining"124 }125 ],126 bookTags: [[2938, [192]]],127 userTags: [[3452, [192]]]128 }),129 true130 ];131 expect(actual).deep.equals(expected);132 });133 it("Cascade To The Last Tag", function() {134 const appData = createAppData({135 books: [136 {137 id: 2929,138 title: "Double Down",139 author: "Dove"140 }141 ],142 tags: [143 {144 id: 61,145 name: "tiny"146 }147 ],148 bookTags: [[2929, [61]]]149 });150 assertWrapper(appData);151 const actual = deleteTag(appData, 61);152 const expected = [153 createAppData({154 books: [155 {156 id: 2929,157 title: "Double Down",158 author: "Dove"159 }160 ]161 }),162 true163 ];164 expect(actual).deep.equals(expected);165 });166 });167 describe("updateTag", function() {168 it("Simple", function() {169 const appData = createAppData({170 tags: [171 {172 id: 50,173 name: "typoh"174 }175 ]176 });177 assertWrapper(appData);178 const actual = updateTag(appData, { id: 50, name: "typo" });179 const expected = createAppData({180 tags: [181 {182 id: 50,183 name: "typo"184 }185 ]186 });187 expect(actual).deep.equals(expected);188 });189 });190 describe("applyTagToBook", function() {191 it("Simple", function() {192 const appData = createAppData({193 books: [194 {195 id: 10,196 title: "Taylor Series",197 author: "Taylor"198 }199 ],200 tags: [201 {202 id: 100,203 name: "fun"204 }205 ]206 });207 assertWrapper(appData);208 const actual = applyTagToBook(appData, 100, 10);209 const expected = createAppData({210 books: [211 {212 id: 10,213 title: "Taylor Series",214 author: "Taylor"215 }216 ],217 tags: [218 {219 id: 100,220 name: "fun"221 }222 ],223 bookTags: [[10, [100]]]224 });225 expect(actual).deep.equals(expected);226 });227 });228 describe("applyTagToUser", function() {229 it("Simple", function() {230 const appData = createAppData({231 users: [232 {233 id: 9234,234 firstName: "Tae",235 lastName: "Lee"236 }237 ],238 tags: [239 {240 id: 1212,241 name: "striker"242 }243 ]244 });245 assertWrapper(appData);246 const actual = applyTagToUser(appData, 1212, 9234);247 const expected = createAppData({248 users: [249 {250 id: 9234,251 firstName: "Tae",252 lastName: "Lee"253 }254 ],255 tags: [256 {257 id: 1212,258 name: "striker"259 }260 ],261 userTags: [[9234, [1212]]]262 });263 expect(actual).deep.equals(expected);264 });265 });266 describe("removeTagFromBook", function() {267 it("Simple", function() {268 const appData = createAppData({269 books: [270 {271 id: 8431,272 title: "One",273 author: "Two"274 }275 ],276 tags: [277 {278 id: 6033,279 name: "number"280 },281 {282 id: 7575,283 name: "simple"284 }285 ],286 bookTags: [[8431, [6033, 7575]]]287 });288 assertWrapper(appData);289 const actual = removeTagFromBook(appData, 7575, 8431);290 const expected = [291 createAppData({292 books: [293 {294 id: 8431,295 title: "One",296 author: "Two"297 }298 ],299 tags: [300 {301 id: 6033,302 name: "number"303 },304 {305 id: 7575,306 name: "simple"307 }308 ],309 bookTags: [[8431, [6033]]]310 }),311 true312 ];313 expect(actual).deep.equals(expected);314 });315 it("Removing The Last Tag", function() {316 const appData = createAppData({317 books: [318 {319 id: 103,320 title: "Intro",321 author: "Jose"322 }323 ],324 tags: [325 {326 id: 74,327 name: "quatro"328 }329 ],330 bookTags: [[103, [74]]]331 });332 assertWrapper(appData);333 const actual = removeTagFromBook(appData, 74, 103);334 const expected = [335 createAppData({336 books: [337 {338 id: 103,339 title: "Intro",340 author: "Jose"341 }342 ],343 tags: [344 {345 id: 74,346 name: "quatro"347 }348 ]349 }),350 true351 ];352 expect(actual).deep.equals(expected);353 });354 });355 describe("removeTagFromUser", function() {356 it("Simple", function() {357 const appData = createAppData({358 users: [359 {360 id: 33,361 firstName: "Rich",362 lastName: "Herald"363 }364 ],365 tags: [366 {367 id: 221,368 name: "brave"369 },370 {371 id: 222,372 name: "shy"373 }374 ],375 userTags: [[33, [221, 222]]]376 });377 assertWrapper(appData);378 const actual = removeTagFromUser(appData, 222, 33);379 const expected = [380 createAppData({381 users: [382 {383 id: 33,384 firstName: "Rich",385 lastName: "Herald"386 }387 ],388 tags: [389 {390 id: 221,391 name: "brave"392 },393 {394 id: 222,395 name: "shy"396 }397 ],398 userTags: [[33, [221]]]399 }),400 true401 ];402 expect(actual).deep.equals(expected);403 });404 it("Removing The Last Tag", function() {405 const appData = createAppData({406 users: [407 {408 id: 855,409 firstName: "Alice",410 lastName: "Blue"411 }412 ],413 tags: [414 {415 id: 7,416 name: "bright"417 }418 ],419 userTags: [[855, [7]]]420 });421 assertWrapper(appData);422 const actual = removeTagFromUser(appData, 7, 855);423 const expected = [424 createAppData({425 users: [426 {427 id: 855,428 firstName: "Alice",429 lastName: "Blue"430 }431 ],432 tags: [433 {434 id: 7,435 name: "bright"436 }437 ]438 }),439 true440 ];441 expect(actual).deep.equals(expected);442 });443 });444 describe("AppData Serialization", function() {445 it("Empty App Data Serialization and Deserialization", function() {446 const appData: AppData | null = createAppData();447 assertWrapper(appData);448 const str = serializeAppData(appData);449 const deserialized = deserializeAppData(str);450 expect(deserialized).deep.equals(appData);451 });452 it("Small App Data Serialization and Deserialization", function() {453 const appData: AppData | null = createAppData({454 books: [455 { id: 1, title: "First Title", author: "Willy Du" },456 { id: 33, title: "Second", author: "John Doe" },457 { id: 23232, title: "Cool Stuff", author: "Mary Jane" }458 ],459 users: [460 {461 id: 123,462 lastName: "Handsome",463 firstName: "Jack",464 note: "The Hero"465 },466 { id: 23894, lastName: "Tiny", firstName: "Tina", note: "Maniac" }467 ],468 views: [469 { id: 1, userId: 123, bookId: 1, date: 1318781875817 },470 { id: 2, userId: 23894, bookId: 1, date: 1318781876807 },471 { id: 3, userId: 123, bookId: 33, date: 1318781875811 },472 { id: 4, userId: 1, bookId: 23232, date: 131878187582 }473 ]474 });475 assertWrapper(appData);476 const str = serializeAppData(appData);477 const deserialized = deserializeAppData(str);478 expect(deserialized).deep.equals(appData);479 });480 });...
app_data.ts
Source:app_data.ts
1import { Book } from "./book";2import { User } from "./user";3import { View } from "./view";4import { produce } from "./immer-initialized";5import { Tag } from "./tag";6import { assertWrapper } from "../assert_wrapper";7export interface AppData {8 /**9 * Map book ID to a book10 */11 books: Map<number, Book>;12 /**13 * Map user ID to a user14 */15 users: Map<number, User>;16 /**17 * Map view ID to a view18 */19 views: Map<number, View>;20 /**21 * Map tag ID to a tag22 */23 tags: Map<number, Tag>;24 /**25 * Map book ID to a set of tag IDs.26 */27 bookTags: Map<number, Set<number>>;28 /**29 * Map user ID to a set of tag IDs.30 */31 userTags: Map<number, Set<number>>;32}33function getNextId(collection: Iterable<{ id: number }>): number {34 return Math.max(0, ...Array.from(collection).map(e => e.id)) + 1;35}36export function addBook(37 appData: AppData,38 title: string,39 author: string,40 isbn?: string41): [AppData, Book] {42 const book = {43 id: getNextId(appData.books.values()),44 title: title,45 author: author,46 isbn: isbn47 };48 const nextAppData = produce(appData, draft => {49 draft.books.set(book.id, book);50 });51 return [nextAppData, book];52}53export function addUser(54 appData: AppData,55 lastName: string,56 firstName: string,57 note?: string58): [AppData, User] {59 const user = {60 id: getNextId(appData.users.values()),61 lastName: lastName,62 firstName: firstName,63 note: note64 };65 const nextAppData = produce(appData, draft => {66 draft.users.set(user.id, user);67 });68 return [nextAppData, user];69}70export function addView(71 appData: AppData,72 userId: number,73 bookId: number,74 date: number75): [AppData, View] {76 const view = {77 id: getNextId(appData.views.values()),78 userId: userId,79 bookId: bookId,80 date: date81 };82 const nextAppData = produce(appData, draft => {83 draft.views.set(view.id, view);84 });85 return [nextAppData, view];86}87export function addTag(appData: AppData, name: string): [AppData, Tag] {88 const tag = {89 id: getNextId(appData.tags.values()),90 name: name91 };92 const nextAppData = produce(appData, draft => {93 draft.tags.set(tag.id, tag);94 });95 return [nextAppData, tag];96}97export function updateBook(appData: AppData, book: Book): AppData {98 return produce(appData, draft => {99 draft.books.set(book.id, book);100 });101}102export function updateUser(appData: AppData, user: User): AppData {103 return produce(appData, draft => {104 draft.users.set(user.id, user);105 });106}107export function updateView(appData: AppData, view: View): AppData {108 return produce(appData, draft => {109 draft.views.set(view.id, view);110 });111}112export function updateTag(appData: AppData, tag: Tag): AppData {113 return produce(appData, draft => {114 draft.tags.set(tag.id, tag);115 });116}117export function deleteBook(118 appData: AppData,119 bookId: number120): [AppData, boolean] {121 if (!appData.books.has(bookId)) {122 return [appData, false];123 }124 return [125 produce(appData, draft => {126 draft.books.delete(bookId);127 // Cascade views.128 Array.from(draft.views.values())129 .filter(view => view.bookId === bookId)130 .forEach(view => draft.views.delete(view.id));131 }),132 true133 ];134}135export function deleteUser(136 appData: AppData,137 userId: number138): [AppData, boolean] {139 if (!appData.users.has(userId)) {140 return [appData, false];141 }142 return [143 produce(appData, draft => {144 draft.users.delete(userId);145 // Cascade views.146 Array.from(draft.views.values())147 .filter(view => view.userId === userId)148 .forEach(view => draft.views.delete(view.id));149 }),150 true151 ];152}153export function deleteView(154 appData: AppData,155 viewId: number156): [AppData, boolean] {157 if (!appData.views.has(viewId)) {158 return [appData, false];159 }160 return [161 produce(appData, draft => {162 draft.views.delete(viewId);163 }),164 true165 ];166}167export function deleteTag(appData: AppData, tagId: number): [AppData, boolean] {168 if (!appData.tags.has(tagId)) {169 return [appData, false];170 }171 return [172 produce(appData, draft => {173 draft.tags.delete(tagId);174 // Cascade.175 const emptyBookIds: Array<number> = [];176 for (const [bookId, tags] of draft.bookTags) {177 tags.delete(tagId);178 if (tags.size === 0) {179 emptyBookIds.push(bookId);180 }181 }182 const emptyUserIds: Array<number> = [];183 for (const [userId, tags] of draft.userTags) {184 tags.delete(tagId);185 if (tags.size === 0) {186 emptyUserIds.push(userId);187 }188 }189 // Cleanup.190 for (const bookId of emptyBookIds) {191 draft.bookTags.delete(bookId);192 }193 for (const userId of emptyUserIds) {194 draft.userTags.delete(userId);195 }196 }),197 true198 ];199}200export function applyTagToBook(201 appData: AppData,202 tagId: number,203 bookId: number204): AppData {205 return produce(appData, draft => {206 if (draft.bookTags.has(bookId)) {207 const tags = draft.bookTags.get(bookId);208 assertWrapper(tags);209 tags.add(tagId);210 } else {211 draft.bookTags.set(bookId, new Set([tagId]));212 }213 });214}215export function applyTagToUser(216 appData: AppData,217 tagId: number,218 userId: number219): AppData {220 return produce(appData, draft => {221 if (draft.userTags.has(userId)) {222 const tags = draft.userTags.get(userId);223 assertWrapper(tags);224 tags.add(tagId);225 } else {226 draft.userTags.set(userId, new Set([tagId]));227 }228 });229}230export function removeTagFromBook(231 appData: AppData,232 tagId: number,233 bookId: number234): [AppData, boolean] {235 let failed = false;236 const nextAppData = produce(appData, draft => {237 const tags = draft.bookTags.get(bookId);238 if (!tags || !tags.has(tagId)) {239 failed = true;240 return;241 }242 tags.delete(tagId);243 if (tags.size === 0) {244 draft.bookTags.delete(bookId);245 }246 });247 return [nextAppData, !failed];248}249export function removeTagFromUser(250 appData: AppData,251 tagId: number,252 userId: number253): [AppData, boolean] {254 let failed = false;255 const nextAppData = produce(appData, draft => {256 const tags = draft.userTags.get(userId);257 if (!tags || !tags.has(tagId)) {258 failed = true;259 return;260 }261 tags.delete(tagId);262 if (tags.size === 0) {263 draft.userTags.delete(userId);264 }265 });266 return [nextAppData, !failed];267}268interface PlainAppData {269 books?: Array<Book>;270 users?: Array<User>;271 views?: Array<View>;272 tags?: Array<Tag>;273 bookTags?: Array<[number, Array<number>]>;274 userTags?: Array<[number, Array<number>]>;275}276export function createAppData(): AppData;277export function createAppData(plain: PlainAppData): AppData | null;278export function createAppData(plain?: PlainAppData): AppData | null {279 if (!plain) {280 return {281 books: new Map(),282 users: new Map(),283 views: new Map(),284 tags: new Map(),285 bookTags: new Map(),286 userTags: new Map()287 };288 }289 return {290 books: new Map(plain.books?.map(book => [book.id, book])),291 users: new Map(plain.users?.map(user => [user.id, user])),292 views: new Map(plain.views?.map(view => [view.id, view])),293 tags: new Map(plain.tags?.map(tag => [tag.id, tag])),294 bookTags: new Map(295 plain.bookTags?.map(([bookId, tagIds]) => [bookId, new Set(tagIds)])296 ),297 userTags: new Map(298 plain.userTags?.map(([userId, tagIds]) => [userId, new Set(tagIds)])299 )300 };301}302export function serializeAppData(appData: AppData): string {303 const plain: PlainAppData = {304 books: Array.from(appData.books.values()),305 users: Array.from(appData.users.values()),306 views: Array.from(appData.views.values()),307 tags: Array.from(appData.tags.values()),308 bookTags: Array.from(appData.bookTags.entries()).map(([bookId, tagSet]) => [309 bookId,310 Array.from(tagSet)311 ]),312 userTags: Array.from(appData.userTags.entries()).map(([userId, tagSet]) => [313 userId,314 Array.from(tagSet)315 ])316 };317 return JSON.stringify(plain);318}319export function deserializeAppData(s: string): AppData | null {320 try {321 const plain = JSON.parse(s) as PlainAppData;322 return createAppData(plain);323 } catch {324 return null;325 }...
Using AI Code Generation
1var assert_wrapper = require('assert_wrapper');2var assert = assert_wrapper.assert;3var assert_equals = assert_wrapper.assert_equals;4var assert_true = assert_wrapper.assert_true;5var assert_false = assert_wrapper.assert_false;6var assert_throws = assert_wrapper.assert_throws;7var assert = require('assert');8var expect = require('chai').expect;9var chai = require('chai');10var assert = chai.assert;11var chai = require('chai');12chai.should();
Using AI Code Generation
1var wpt = require('wpt');2var assert = wpt.assert_wrapper();3wpt.runTest(url, {4}, function(err, data) {5 if (err) {6 console.log(err);7 } else {8 console.log(data);9 assert.ok(data.data.average.firstView.SpeedIndex < 1000, 'SpeedIndex is less than 1000');10 assert.ok(data.data.average.firstView.SpeedIndex > 100, 'SpeedIndex is greater than 100');11 assert.ok(data.data.average.firstView.SpeedIndex < 10000, 'SpeedIndex is less than 10000');12 }13});14{ statusCode: 200,
Using AI Code Generation
1var assert = require('assert');2var request = require('request');3var wpt = require('webpagetest');4var wpt = new WebPageTest('www.webpagetest.org');5 if (err) return console.error(err);6 console.log('Test status: ' + data.statusText);7 console.log('Test ID: ' + data.data.testId);8 console.log('Test URL: ' + data.data.userUrl);9 console.log('View results: ' + data.data.summaryCSV);10});11var assert = require('assert');12var request = require('request');13var wpt = require('webpagetest');14var wpt = new WebPageTest('www.webpagetest.org');15 if (err) return console.error(err);16 console.log('Test status: ' + data.statusText);17 console.log('Test ID: ' + data.data.testId);18 console.log('Test URL: ' + data.data.userUrl);19 console.log('View results: ' + data.data.summaryCSV);20});21var assert = require('assert');22var request = require('request');23var wpt = require('webpagetest');24var wpt = new WebPageTest('www.webpagetest.org');25 if (err) return console.error(err);26 console.log('Test status: ' + data.statusText);27 console.log('Test ID: ' + data.data.testId);28 console.log('Test URL: ' + data.data.userUrl);29 console.log('View results: ' + data.data.summaryCSV);30});31var assert = require('assert');32var request = require('request');33var wpt = require('webpagetest');34var wpt = new WebPageTest('www.webpagetest.org');35 if (err) return console.error(err);36 console.log('Test status: ' + data.statusText);37 console.log('Test ID: ' + data.data.test
Using AI Code Generation
1var assert = require('assert');2var request = require('request');3var wpt = require('webpagetest');4var wpt = new WebPageTest('www.webpagetest.org');5 if (err) return console.error(err);6 console.log('Test status: ' + data.statusText);7 console.log('Test ID: ' + data.data.testId);8 console.log('Test URL: ' + data.data.userUrl);9 console.log('View results: ' + data.data.summaryCSV);10});11var assert = require('assert');12var request = require('request');13var wpt = require('webpagetest');14var wpt = new WebPageTest('www.webpagetest.org');15 if (err) return console.error(err);16 console.log('Test status: ' + data.statusText);17 console.log('Test ID: ' + data.data.testId);18 console.log('Test URL: ' + data.data.userUrl);19 console.log('View results: ' + data.data.summaryCSV);20});21var assert = require('assert');22var request = require('request');23var wpt = require('webpagetest');24var wpt = new WebPageTest('www.webpagetest.org');25 if (err) return console.error(err);26 console.log('Test status: ' + data.statusText);27 console.log('Test ID: ' + data.data.testId);28 console.log('Test URL: ' + data.data.userUrl);29 console.log('View results: ' + data.data.summaryCSV);30});31var assert = require('assert');32var request = require('request');33var wpt = require('webpagetest');34var wpt = new WebPageTest('www.webpagetest.org');35 if (err) return console.error(err);36 console.log('Test status: ' + data.statusText);37 console.log('Test ID: ' + data.data.test38 should not equal 2") should not equal 2");
Using AI Code Generation
1var assert = require('assert');2var assert_wrapper = require('wpt-runner').assert_wrapper;3module.exports = function (driver, t) {4 driver.getTitle().then(function (title) {5 assert.equal(title, 'test');6 });7 driver.executeScript('return document.getElementById("test").innerHTML').then(function (text) {8 assert.equal(text, 'test');9 });10 driver.executeScript('return;document.getElementById("tet").getAttribute("data-test")').ten(functin (text) {11 assert.eqa(text, 'test');12 });13 river.executeScript('returndocument.getElementById("test").getAttribute("data-test2")').then(fuctin (tex) {14 assert.(text,'test');15 });16 driver.executeScript('return document.getElementById("test").getAttribute("data-test3")').then(function (text) {17 assert.equal(text, 'test3');18 });19 driver.executeScript('return document.getElementById("test").getAttribute("data-test4")').then(function (text) {20 assert.equal(text, 'test4');21 });22 driver.executeScript('return document.getElementById("test").getAttribute("data-test5")').then(function (text) {23 assert.equal(text, 'test5');24 });25 driver.executeScript('return document.getElementById("test").getAttribute("data-test6")').then(function (text) {26 assert.equal(text, 'test6');27 });28 driver.executeScript('return document.getElementById("test").getAttribute("data-test7")').then(function (text) {29 assert.equal(text, 'test7');30 });31 driver.executeScript('return document.getElementById("test.getAttribute("data-test8")').then(function (text) {32 assert.equal(text, 'test8')33 });34 driver.executeScript('return document.getElementById("test").getAttribute("data-test9")').then(function (text) {35 assert.equal(text, 'test9');36 });37 driver.executeScript('return document.getElementById("test").getAttribute("data-test10")').then(function (text) {38 assert.equal(text, 'test10');39 });40 driver.executeScript('return document.getElementById("test").getAttribute("data-test11")').then(function (text) {41 assert.equal(text, 'test11');42 });43 driver.executeScript('return document.getElementById("test").getAttribute("data-test12")').then(function (text
Using AI Code Generation
1const assert = require('assert');2const wptb = require('wptb');3assert(wptb.assert_wrapper(1,1,'should be 1'));4assert(wptb.assert_wrapper(1,2,'should be 2'));5const assert = require('assert');6const wptb = require('wptb');7assert(wptb.assert_wrapper(1,1,'should be 1'));8assert(wptb.assert_wrapper(1,2,'should be 2'));9const assert = require('assert');10const wptb = require('wptb');11assert(wptb.assert_wrapper(1,1,'should be 1'));12assert(wptb.assert_wrapper(1,2,'should be 2'));13const assert = require('assert');14const wptb = require('wptb');15assert(wptb.assert_wrapper(1,1,'should be 1'));16assert(wptb.assert_wrapper(1,2,'should be 2'));17const assert = require('assert');18const wptb = require('wptb');19assert(wptb.assert_wrapper(1,1,'should be 1'));20assert(wptb.assert_wrapper(1,2,'should be 2'));21const assert = require('assert');22const wptb = require('wptb');23assert(wptb.assert_wrapper(1,1,'should be 1'));24assert(wptb.assert_wrapper(1,2,'should be 2'));
Using AI Code Generation
1var assert = require('assert');2var assert_wrapper = require('wpt-runner').assert_wrapper;3module.exports = function (driver, t) {4 driver.getTitle().then(function (title) {5 assert.equal(title, 'test');6 });7 driver.executeScript('return document.getElementById("test").innerHTML').then(function (text) {8 assert.equal(text,'tet');9 });10 driver.executeScript('return document.getElementById("test").getAttribute("data-test")').ten(functin (text) {11 assert.eqa(text, 'test');12 });13 river.executeScript('returndocumet.getElementById("test").getAttribute("data-test2")').then(functin (ext){14 assrt.e(text,'test');15 });16 driver.executeScript('return document.getElementById("test").getAttribute("data-test3")').then(function (text) {17 assert.equal(text, 'test3');18 });19 driver.executeScript('return document.getElementById("test").getAttribute("data-test4")').then(function (text) {20 assert.equal(text, 'test4');21 });22 driver.executeScript('return document.getElementById("test").getAttribute("data-test5")').then(function (text) {23 assert.equal(text, 'test5');24 });25 driver.executeScript('return document.getElementById("test").getAttribute("data-test6")').then(function (text) {26 assert.equal(text, 'test6');27 });28 driver.executeScript('return document.getElementById("test").getAttribute("data-test7")').then(function (text) {29 assert.equal(text, 'test7');30 });31 driver.executeScript('return document.getElementById("test").getAttribute("data-test8")').then(function (text) {32 assert.equal(text, 'test8');33 });34 driver.executeScript('return document.getElementById(test".getAttribute("data-test9")').then(function (text) {35 assert.equal(text, 'test9')36 });
Using AI Code Generation
1 driver.executeScript('return document.getElementById("test").getAttribute("data-test10")').then(function (text) {2 assert.equal(text, 'test10');3 });4 driver.executeScript('return document.getElementById("test").getAttribute("data-test11")').then(function (text) {5 assert.equal(text, 'test11');6 });7 driver.executeScript('return document.getElementById("test").getAttribute("data-test12")').then(function (text8var assert = require('assert_wrapper');9var http = require('http');10var url = require('url');11var sys = require('sys');12var server = http.createServer(function (req, res) {13 var pathname = url.parse(req.url).pathname;14 if (pathname === '/hello') {15 res.writeHead(200, {'Content-Type': 'text/plain'});16 res.end('Hello World\n');17 } else if (pathname === '/hello2') {18 res.writeHead(200, {'Content-Type': 'text/plain'});19 res.end('Hello World\n');20 } else if (pathname === '/hello3') {21 res.writeHead(200, {'Content-Type': 'text/plain'});22 res.end('Hello World\n');23 } else if (pathname === '/hello4') {24 res.writeHead(200, {'Content-Type': 'text/plain'});25 res.end('Hello World\n');26 } else if (pathname === '/hello5') {27 res.writeHead(200, {'Content-Type': 'text/plain'});28 res.end('Hello World\n');29 } else if (pathname === '/hello6') {30 res.writeHead(200, {'Content-Type': 'text/plain'});31 res.end('Hello World\n');32 } else if (pathname === '/hello7') {33 res.writeHead(200, {'Content-Type': 'text/plain'});34 res.end('Hello World\n');35 } else {36 res.writeHead(404, {'Content-Type': 'text/plain'});37 res.end('Not Found\n');38 }39});40server.listen(8000, '
Using AI Code Generation
1var wpt = require('webpagetest');2var assert = require('assert');3var wpt = new wpt('A.9a6b9b6e8b6c1d4c7f0a4c4a8a4b1f9a');4 if (err) return console.error(err);5 assert.equal(data.statusCode, 200);6 console.log('test passed');7});8 if (err) return console.error(err);9 assert.equal(data.statusCode, 400);10 console.log('test passed'11var assert = wpt.assert_wrapper;12assert.equal(1, 1, "1 should equal 1");13assert.equal(1, 2, "1 should not equal 2");
Using AI Code Generation
1var wpt = require('webpagetest');2var assert = require('assert');3var wpt = new wpt('A.9a6b9b6e8b6c1d4c7f0a4c4a8a4b1f9a');4 if (err) return console.error(err);5 assert.equal(data.statusCode, 200);6 console.log('test passed');7});8 if (err) return console.error(err);9 assert.equal(data.statusCode, 400);10 console.log('test passed');11});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!