import playwright from 'playwright'; import faker from 'faker'; import random from 'random'; import assert from "assert"; import { v4 as uuid } from "uuid"; import fs from "fs"; import url from "url"; import path from "path"; import { User } from "./models.js"; const WAIT_TIME = 5000; const HEADLESS = !process.env.PLAYVIEW; const COVERAGE = process.env.NODE_V8_COVERAGE; export const tid = (name) => `[data-testid="${name}"]`; export const form = async (page, fields, button_id) => { for(const [key, value] of Object.entries(fields)) { if(typeof value === "boolean") { if(value) { await page.check(key); } else { await page.uncheck(key); } } else { // it's another input to fill await page.fill(key, value); } } if(button_id) { await page.click(button_id); } } export const playstart = async (url) => { if(!HEADLESS) console.log("Running playwright in visible mode (not HEADLESS)."); if(COVERAGE) console.log(`Coverage reports going to ${COVERAGE}.`); const browser = await playwright['chromium'].launch({headless: HEADLESS}); const context = await browser.newContext(); const p = await context.newPage(); if(COVERAGE) { await p.coverage.startJSCoverage(); } p.on('console', async msg => { console.debug(`CONSOLE ${msg.type()}>>`, msg) }); await p.goto(url); return {browser, context, p}; } export const playstop = async (browser, p) => { if(COVERAGE) { const coverage = await p.coverage.stopJSCoverage(); for(const entry of coverage) { entry.url = path.join(process.cwd(), "public", url.parse(entry.url).pathname); } const v8out = {result: coverage, timestamp: Date.now()}; fs.writeFileSync(`${COVERAGE}/${uuid()}.json`, JSON.stringify(v8out)); } await browser.close(); } export const wait = async (p, css_id) => { try { await p.waitForSelector(css_id, { timeout: WAIT_TIME }); } catch(error) { console.error(error, `!!!!!!!!!!!!!!!!!!!!!!!!!!!! Failed waiting for id ${css_id}`); throw error; } } export const expect = async (t, p, css_id) => { await wait(p, css_id); let tag = await p.$(css_id); let text = tag ? await tag.textContent() : "NULL!"; t.true(text !== null); return text; } export const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } export const random_user = () => { let email = faker.internet.email(); let rnd = random.int(0, 10 * 1000); email = email.replace('@', `${rnd}@`); let full_name = faker.name.findName(); let initials = full_name.split(' ').map(x => x[0]).join(''); let password = faker.internet.password(); assert(password, "Looks like faker is failing at passwords again."); return { email, full_name, initials, password } } export const register_user = async (is_admin=false) => { const rando = random_user(); rando.password_repeat = rando.password; // copy it to keep the original password const user = await User.register({...rando}); if(is_admin) { // make this user an admin user.admin = true; await User.update({id: user.id}, {admin: true}); } // then replace it so we can use it later user.raw_password = rando.password; return user; } /* A helper function for other tests to use logins. */ export const login = async (t, p, with_user) => { const user = with_user ? with_user : await register_user(); await expect(t, p, tid("login-form")); // fill out correct form, and redirect to watch await p.fill('#email', user.email); await p.fill("#password", user.raw_password); await p.click(tid('login-button')); await sleep(1000); return user; }