Path: blob/main/plugins/default-browser-emulator/test/polyfills.test.ts
1029 views
import * as http from 'http';1import { inspect } from 'util';2import * as Helpers from '@secret-agent/testing/helpers';3import { ITestHttpServer } from '@secret-agent/testing/helpers';4import Puppet from '@secret-agent/puppet';5import IPuppetContext from '@secret-agent/interfaces/IPuppetContext';6import Log from '@secret-agent/commons/Logger';7import CorePlugins from '@secret-agent/core/lib/CorePlugins';8import { IBoundLog } from '@secret-agent/interfaces/ILog';9import { getOverrideScript } from '../lib/DomOverridesBuilder';10import BrowserEmulator from '../index';11import DomExtractor = require('./DomExtractor');1213const { log } = Log(module);14const selectBrowserMeta = BrowserEmulator.selectBrowserMeta();1516let puppet: Puppet;17let httpServer: ITestHttpServer<http.Server>;18let context: IPuppetContext;19beforeAll(async () => {20puppet = new Puppet(selectBrowserMeta.browserEngine);21Helpers.onClose(() => puppet.close(), true);22await puppet.start();23const plugins = new CorePlugins({ selectBrowserMeta }, log as IBoundLog);24plugins.browserEmulator.onNewPuppetPage = null;25context = await puppet.newContext(plugins, log);26Helpers.onClose(() => context.close().catch(), true);27httpServer = await Helpers.runHttpServer({ onlyCloseOnFinal: true });28});2930afterAll(Helpers.afterAll);31afterEach(Helpers.afterEach);3233const debug = process.env.DEBUG || false;3435test('it should be able to add polyfills', async () => {36const page = await createPage();3738const objectTestProperties = {39length: {40_$type: 'number',41_$flags: 'c',42_$value: 0,43},44name: {45_$type: 'string',46_$flags: 'c',47_$value: 'ObjectTest',48},49arguments: {50_$type: 'object',51_$flags: '',52_$value: null,53},54caller: {55_$type: 'object',56_$flags: '',57_$value: null,58},59prototype: {60_$protos: ['Object.prototype'],61creationTime: {62_$flags: 'ce',63_$accessException: 'TypeError: Illegal invocation',64_$get: 'function get creationTime() { [native code] }',65_$getToStringToString: 'function toString() { [native code] }',66},67'Symbol(Symbol.toStringTag)': {68_$type: 'string',69_$flags: 'c',70_$value: 'ObjectTest',71},72_$type: 'object',73_$flags: '',74},75'new()': {76_$constructorException: "TypeError: Cannot read property '0' of undefined",77_$type: 'constructor',78},79_$type: 'function',80_$function: 'function ObjectTest() { [native code] }',81_$flags: 'cw',82_$value: 'function ObjectTest() { [native code] }',83_$invocation: "TypeError: Cannot read property '0' of undefined",84};85const chromeProperty = {86_$flags: 'ce',87_$type: 'string',88_$value: 'I am chrome',89};90await page.addNewDocumentScript(91getOverrideScript('polyfill.add', {92itemsToAdd: [93{94path: 'window',95propertyName: 'chromey',96prevProperty: 'Atomics',97property: chromeProperty,98},99{100path: 'window',101propertyName: 'ObjectTest',102prevProperty: 'chromey',103property: objectTestProperties,104},105],106}).script,107false,108);109await Promise.all([110page.navigate(httpServer.url),111page.mainFrame.waitOn('frame-lifecycle', event => event.name === 'load'),112]);113114const json = await page.mainFrame.evaluate(115`new (${DomExtractor.toString()})('window').run(window, 'window', ['windowKeys','chromey','ObjectTest'])`,116false,117);118const result = JSON.parse(json as any);119120const windowKeys = result.windowKeys;121const window = result.window;122// test chrome property123if (debug) {124console.log('chromey', inspect(window.chromey, false, null, true));125}126expect(window.chromey).toStrictEqual(chromeProperty);127expect(windowKeys.indexOf('chromey')).toBe(windowKeys.indexOf('Atomics') + 1);128129// test ObjectTest property130if (debug) {131console.log('ObjectTest', inspect(window.ObjectTest, false, null, true));132}133expect(window.ObjectTest).toStrictEqual(objectTestProperties);134expect(windowKeys.indexOf('ObjectTest')).toBe(windowKeys.indexOf('chromey') + 1);135}, 60e3);136137test('it should be able to remove properties', async () => {138const page = await createPage();139140await page.addNewDocumentScript(141getOverrideScript('polyfill.remove', {142itemsToRemove: [143{ path: 'window', propertyName: 'Atomics' },144{ path: 'window.Array', propertyName: 'from' },145],146}).script,147false,148);149await Promise.all([150page.navigate(httpServer.url),151page.mainFrame.waitOn('frame-lifecycle', event => event.name === 'load'),152]);153154expect(await page.mainFrame.evaluate(`!!window.Atomics`, false)).not.toBeTruthy();155expect(await page.mainFrame.evaluate(`!!Array.from`, false)).not.toBeTruthy();156});157158test('it should be able to change properties', async () => {159const page = await createPage();160161await page.addNewDocumentScript(162getOverrideScript('polyfill.modify', {163itemsToModify: [164{165path: 'window.Navigator.prototype.registerProtocolHandler.name',166propertyName: '_$value',167property: 'notTheRightName',168},169{170path: 'window.Navigator.prototype.registerProtocolHandler',171propertyName: '_$function',172property: 'function registerProtocolHandler() { [unnative code] }',173},174],175}).script,176false,177);178await Promise.all([179page.navigate(httpServer.url),180page.mainFrame.waitOn('frame-lifecycle', event => event.name === 'load'),181]);182183const protocolToString = await page.mainFrame.evaluate(184`window.Navigator.prototype.registerProtocolHandler.toString()`,185false,186);187const protocolName = await page.mainFrame.evaluate(188`window.Navigator.prototype.registerProtocolHandler.name`,189false,190);191192expect(protocolName).toBe('notTheRightName');193expect(protocolToString).toBe('function registerProtocolHandler() { [unnative code] }');194});195196test('it should be able to change property order', async () => {197const page = await createPage();198199const startNavigatorKeys = (await page.mainFrame.evaluate(200`Object.keys(window.Navigator.prototype)`,201false,202)) as string[];203204await page.addNewDocumentScript(205getOverrideScript('polyfill.reorder', {206itemsToReorder: [207{208path: 'window.Navigator.prototype',209propertyName: startNavigatorKeys[10],210throughProperty: startNavigatorKeys[12],211prevProperty: startNavigatorKeys[1],212},213{214path: 'window.Navigator.prototype',215propertyName: startNavigatorKeys[18],216throughProperty: startNavigatorKeys[18],217prevProperty: startNavigatorKeys[12],218},219],220}).script,221false,222);223await new Promise(setImmediate);224await Promise.all([225page.navigate(httpServer.url),226page.mainFrame.waitOn('frame-lifecycle', event => event.name === 'load'),227]);228229const keyOrder = (await page.mainFrame.evaluate(230`Object.keys(window.Navigator.prototype)`,231false,232)) as string[];233234const prop1Index = keyOrder.indexOf(startNavigatorKeys[10]);235expect(keyOrder[prop1Index - 1]).toBe(startNavigatorKeys[1]);236237const prop2Index = keyOrder.indexOf(startNavigatorKeys[18]);238expect(keyOrder[prop2Index - 1]).toBe(startNavigatorKeys[12]);239});240241test('it should be able to change window property order', async () => {242const page = await createPage();243const windowKeys = await page.mainFrame.evaluate(`Object.keys(window)`, false);244245const itemsToReorder = [246{247path: 'window',248propertyName: windowKeys[10],249throughProperty: windowKeys[12],250prevProperty: windowKeys[1],251},252{253path: 'window',254propertyName: windowKeys[18],255throughProperty: windowKeys[18],256prevProperty: windowKeys[12],257},258{259path: 'window',260propertyName: windowKeys[25],261throughProperty: windowKeys[50],262prevProperty: windowKeys[23],263},264];265await page.addNewDocumentScript(266getOverrideScript('polyfill.reorder', {267itemsToReorder,268}).script,269false,270);271await Promise.all([272page.navigate(httpServer.url),273page.mainFrame.waitOn('frame-lifecycle', event => event.name === 'load'),274]);275const windowKeysAfter = (await page.mainFrame.evaluate(`Object.keys(window)`, false)) as string[];276277const prop1Index = windowKeysAfter.indexOf(windowKeys[10]);278expect(windowKeysAfter[prop1Index - 1]).toBe(windowKeys[1]);279280const prop2Index = windowKeysAfter.indexOf(windowKeys[18]);281expect(windowKeysAfter[prop2Index - 1]).toBe(windowKeys[12]);282283const prop3Index = windowKeysAfter.indexOf(windowKeys[25]);284expect(windowKeysAfter[prop3Index - 1]).toBe(windowKeys[23]);285286expect(windowKeysAfter.indexOf(windowKeys[26])).toBe(prop3Index + 1);287expect(windowKeysAfter.indexOf(windowKeys[50])).toBe(prop3Index + 25);288}, 10e3);289290async function createPage() {291const page = await context.newPage();292Helpers.onClose(() => page.close());293page.on('page-error', console.log);294if (debug) {295page.on('console', console.log);296}297return page;298}299300301