Ben*_*rri 6 testing automation firebase typescript playwright
我试图确保在每个运行的测试中,我不必登录到我正在测试的平台。为了实现这一目标,我正在实施“重用状态”和“重用身份验证”。但是,Firebase 使用 indexedDB 而不是 Cookie 或 SessionStorage。StorageState 此处不持久保存 indexedDB。也许你知道这个问题的解决方案?
全局设置.ts:
import { Browser, chromium, expect, Page } from "@playwright/test";
async function globalSetup(){
const browser = await chromium.launch({headless: false});
const context = await browser.newContext();
const page: Page = await context.newPage();
await page.goto("<'url'>")
await page.getByLabel('Email').fill('<'email'>');
await page.getByLabel('Password').fill('<'password'>');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect (page.getByRole('link', { name: 'logo' })).toBeVisible({ timeout: 30000 });
//save state
await page.context().storageState({ path: "./LoginAuth.json" });
await browser.close();
}
export default globalSetup;
Run Code Online (Sandbox Code Playgroud)
有用的链接:
https://playwright.dev/docs/auth#reuse-authentication-in-playwright-test https://github.com/microsoft/playwright/issues/11164
也可以将indexedDB存储在storageState中,然后稍后恢复它,尽管你必须跳过一些步骤才能做到这一点。
我所做的是将indexedDB存储在我的localStorage中,这样当您保存storageState时,您就拥有了它的所有内容。它的工作原理是将数据库名称保存为键,将数据库存储对象的字符串化 JSON 保存为值,因此 localStorage 中的每个条目都是一个数据库。我在剧作家的身份验证文档中使用基本身份验证,因此在设置文件中使用以下代码:
import { test as setup } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';
const URL_LOCAL = "http://localhost:8100"
setup('authenticate', async ({ page }) => {
await page.goto(URL_LOCAL);
// Do the login routine here...
await page.evaluate(async () => {
window.localStorage.clear();
window.sessionStorage.clear();
const indexedDB = window.indexedDB;
const dbs = await indexedDB.databases();
for (let dbIndex = 0; dbIndex < dbs.length; dbIndex++) {
const dbInfo = dbs[dbIndex];
const db: IDBDatabase = await new Promise((resolve, reject) => {
let req = indexedDB.open(dbInfo.name as string, dbInfo.version);
req.onsuccess = (event: any) => {
resolve(event.target.result);
}
req.onupgradeneeded = (event: any) => {
resolve(event.target.result);
}
req.onerror = (e) => {
reject(e);
}
});
let dbRes: { [k: string]: any } = {};
for (let objectStorageIndex = 0; objectStorageIndex < db.objectStoreNames.length; objectStorageIndex++) {
const objectStorageName = db.objectStoreNames[objectStorageIndex];
let objectStorageRes: { [k: string]: any } = {};
// Open a transaction to access the firebaseLocalStorage object store
const transaction = db.transaction([objectStorageName], 'readonly');
const objectStore = transaction.objectStore(objectStorageName);
// Get all keys and values from the object store
const getAllKeysRequest = objectStore.getAllKeys();
const getAllValuesRequest = objectStore.getAll();
const keys: any = await new Promise((resolve, reject) => {
getAllKeysRequest.onsuccess = (event: any) => {
resolve(event.target.result);
}
getAllKeysRequest.onerror = (e) => {
reject(e);
}
});
const values: any = await new Promise((resolve, reject) => {
getAllValuesRequest.onsuccess = (event: any) => {
resolve(event.target.result);
}
getAllValuesRequest.onerror = (e) => {
reject(e);
}
});
for (let i = 0; i < keys.length; i++) {
objectStorageRes[keys[i]] = JSON.stringify(values[i]);
}
dbRes[objectStorageName] = objectStorageRes;
}
localStorage.setItem(db.name, JSON.stringify(dbRes));
}
});
await page.context().storageState({ path: authFile });
});
Run Code Online (Sandbox Code Playgroud)
然后我们需要一个额外的文件auth.utils.ts来重建indexedDB数据库,使用以下代码
import { Page } from "@playwright/test";
import { readFileSync } from 'fs';
const URL_LOCAL = "http://localhost:8100"
export const authenticate = async (page: Page) => {
await page.goto(URL_LOCAL);
const auth = JSON.parse(readFileSync('playwright/.auth/user.json', 'utf-8'));
await page.evaluate(async (auth) => {
const indexedDB = window.indexedDB;
const localStorageAuth: any[] = auth.origins[0].localStorage
for (const storage of localStorageAuth) {
const dbName = storage.name;
const dbData = JSON.parse(storage.value as string);
const tables = Object.keys(dbData);
const db: IDBDatabase = await new Promise((resolve, reject) => {
let req = indexedDB.open(dbName as string);
req.onsuccess = (event: any) => {
resolve(event.target.result);
};
req.onupgradeneeded = (event: any) => {
resolve(event.target.result);
};
req.onerror = (e) => {
reject(e);
};
req.onblocked = (event: any) => {
reject(event);
};
});
for (const table of tables) {
const transaction = db.transaction([table], 'readwrite');
const objectStore = transaction.objectStore(table);
for (const key of Object.keys(dbData[table])) {
const value = dbData[table][key];
// Parse value in case of keyPath
let parsedValue = typeof value !== "string" ? JSON.stringify(value) : value;
try {
parsedValue = JSON.parse(parsedValue);
} catch (e) {
// value type is not json, nothing to do
}
if (objectStore.keyPath != null) {
objectStore.put(parsedValue);
} else {
objectStore.put(parsedValue, key);
}
}
}
}
}, auth);
}
Run Code Online (Sandbox Code Playgroud)
最后,将其添加到您希望对其进行身份验证的每个测试中:
import { test, expect } from '@playwright/test';
import { authenticate } from './auth.utils';
/// ...
test.beforeEach(async ({ page }) => {
await authenticate(page);
});
test('example test', async ({ page }) => {
/// Test content
});
/// More tests
Run Code Online (Sandbox Code Playgroud)
我在该主题上找到的大多数答案都非常特定于 Firebase DB,通常 Firebase DB 名称是硬编码的,这不是很灵活。我有多个数据库,因此此代码可以处理多个不同的数据库。
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
601 次 |
| 最近记录: |