Path: blob/main/plugins/default-browser-emulator/test/iframe.test.ts
1029 views
import { Helpers } from '@secret-agent/testing';1import Core, { Session } from '@secret-agent/core';2import { InteractionCommand } from '@secret-agent/interfaces/IInteractions';3import { ITestKoaServer } from '@secret-agent/testing/helpers';4import CoreServerConnection from '@secret-agent/core/server/ConnectionToClient';5import { IPuppetPage } from '@secret-agent/interfaces/IPuppetPage';67let koaServer: ITestKoaServer;8let coreServerConnection: CoreServerConnection;9beforeAll(async () => {10coreServerConnection = Core.addConnection();11Helpers.onClose(() => coreServerConnection.disconnect(), true);12koaServer = await Helpers.runKoaServer();13});14afterAll(Helpers.afterAll);15afterEach(Helpers.afterEach);1617test('should have a chrome object on iframes', async () => {18const page = await createPage();1920const frameType = await page.evaluate(`(() => {21const iframe = document.createElement('iframe');22iframe.srcdoc = 'blank page';23document.body.appendChild(iframe);2425const result = typeof iframe.contentWindow.chrome;26iframe.remove();2728return result;29})();`);30expect(frameType).toBe('object');31});3233test('should not break toString across frames', async () => {34const page = await createPage();3536const toStrings = await page.evaluate(`(() => {37const iframe = document.createElement('iframe');38document.body.appendChild(iframe);3940const contentWindow = iframe.contentWindow;41const fnCallWithFrame = contentWindow.Function.prototype.toString.call(Function.prototype.toString);42const fnToString = Function.toString + '';4344return {45fnToString,46fnCallWithFrame47}48})();`);4950const { fnToString, fnCallWithFrame } = toStrings as any;51expect(fnToString).toBe(fnCallWithFrame);52});5354test('should not break iframe functions', async () => {55const page = await createPage();5657const testFuncReturnValue = 'TESTSTRING';58await page.evaluate(`((returnValue) => {59const { document } = window; // eslint-disable-line60const body = document.querySelector('body');61const iframe = document.createElement('iframe');62iframe.srcdoc = 'foobar';63body.appendChild(iframe);64iframe.contentWindow.mySuperFunction = () => returnValue;65})("${testFuncReturnValue}")`);6667const realReturn = await page.evaluate(68`document.querySelector('iframe').contentWindow.mySuperFunction()`,69);70await page.close();71expect(realReturn).toBe(testFuncReturnValue);72});7374test('should have chrome object in all kinds of iframes', async () => {75const page = await createPage();7677const basiciframe = await page.evaluate(`(() => {78const el = document.createElement('iframe');79document.body.appendChild(el);80return typeof el.contentWindow.chrome;81})()`);8283const sandboxSOiframe = await page.evaluate(`(() => {84const el = document.createElement('iframe');85el.setAttribute('sandbox', 'allow-same-origin');86document.body.appendChild(el);87return typeof el.contentWindow.chrome;88})()`);8990const sandboxSOASiframe = await page.evaluate(`(() => {91const el = document.createElement('iframe');92el.setAttribute('sandbox', 'allow-same-origin allow-scripts');93document.body.appendChild(el);94return typeof el.contentWindow.chrome;95})()`);9697const srcdociframe = await page.evaluate(`(() => {98const el = document.createElement('iframe');99el.srcdoc = 'blank page, boys.';100document.body.appendChild(el);101return typeof el.contentWindow.chrome;102})()`);103104await page.close();105expect(basiciframe).toBe('object');106expect(sandboxSOiframe).toBe('object');107expect(sandboxSOASiframe).toBe('object');108expect(srcdociframe).toBe('object');109});110111test('should have plugins in frames', async () => {112const page = await createPage();113114const plugins = await page.evaluate<number>(`window.navigator.plugins.length`);115const iframePlugins = await page.evaluate<number>(`(() => {116const iframe = document.createElement('iframe');117iframe.srcdoc = 'page intentionally left blank';118document.body.appendChild(iframe);119120return iframe.contentWindow.navigator.plugins.length;121})()`);122expect(plugins).toBe(iframePlugins);123});124125test('should not be able to detect contentWindow overrides', async () => {126const page = await createPage();127128const results = await page.evaluate<any>(`(() => {129const results = {};130131const iframe = document.createElement('iframe');132iframe.srcdoc = 'page intentionally left blank';133document.body.appendChild(iframe);134135const descriptors = Object.getOwnPropertyDescriptors(HTMLIFrameElement.prototype);136results.descriptorToString = descriptors.contentWindow.get.toString();137results.descriptorToStringToString = descriptors.contentWindow.get.toString.toString();138results.windowType = typeof iframe.contentWindow;139results.noProxySignature = !iframe.srcdoc.toString.hasOwnProperty('[[IsRevoked]]');140return results;141})()`);142expect(results.descriptorToString).toBe('function get contentWindow() { [native code] }');143expect(results.descriptorToStringToString).toBe('function toString() { [native code] }');144expect(results.noProxySignature).toBe(true);145expect(results.windowType).toBe('object');146});147148test('should emulate contentWindow features', async () => {149const page = await createPage();150151const results: any = await page.evaluate(`(() => {152const results = {};153154const iframe = document.createElement('iframe');155iframe.srcdoc = 'page intentionally left blank';156document.body.appendChild(iframe);157158results.doesExist = !!iframe.contentWindow; // Verify iframe isn't remapped to main window159results.isNotAClone = iframe.contentWindow !== window; // Verify iframe isn't remapped to main window160results.selfIsNotWindow = iframe.contentWindow.self !== window;161results.selfIsNotWindowTop = iframe.contentWindow.self !== window.top;162results.selfIsAWindow = iframe.contentWindow.self instanceof Window;163results.topIsNotSame = iframe.contentWindow.top !== iframe.contentWindow;164results.frameElementMatches = iframe.contentWindow.frameElement === iframe;165166return results;167})()`);168169await page.close();170171expect(results.doesExist).toBe(true);172expect(results.isNotAClone).toBe(true);173expect(results.selfIsNotWindow).toBe(true);174expect(results.selfIsNotWindowTop).toBe(true);175expect(results.selfIsAWindow).toBe(true);176expect(results.topIsNotSame).toBe(true);177});178179test('should handle a removed frame', async () => {180const meta = await coreServerConnection.createSession();181const tab = Session.getTab(meta);182Helpers.needsClosing.push(tab.session);183await tab.goto(koaServer.baseUrl);184await tab.waitForLoad('PaintingStable');185const navigatorPlatform = await tab.puppetPage.evaluate<boolean>(`(() => {186try {187const numberOfIframes = window.length;188const div = document.createElement('div');189div.setAttribute('style', 'display:none');190document.body.appendChild(div);191div.innerHTML = '<div style="height: 100vh;width: 100vw;position: absolute;left:-10000px;visibility: hidden;"><iframe></iframe></div>';192const iframeWindow = window[numberOfIframes];193div.parentNode.removeChild(div);194return iframeWindow.navigator.platform;195} catch (error) {196console.error(error);197}198})()`);199await tab.puppetPage.close();200expect(navigatorPlatform).toBe(tab.session.plugins.browserEmulator.operatingSystemPlatform);201});202203// only run this test manually204// eslint-disable-next-line jest/no-disabled-tests205test.skip('should not break recaptcha popup', async () => {206const meta = await coreServerConnection.createSession();207const tab = Session.getTab(meta);208Helpers.needsClosing.push(tab.session);209const page = tab.puppetPage;210211await tab.goto('https://www.fbdemo.com/invisible-captcha/index.html');212213await tab.interact([214{215command: InteractionCommand.click,216mousePosition: ['window', 'document', ['querySelector', '#tswname']],217},218{219command: InteractionCommand.type,220keyboardCommands: [{ string: 'foo' }],221},222]);223await tab.interact([224{225command: InteractionCommand.click,226mousePosition: ['window', 'document', ['querySelector', '#tswemail']],227},228{229command: InteractionCommand.type,230keyboardCommands: [{ string: '[email protected]' }],231},232]);233await tab.interact([234{235command: InteractionCommand.click,236mousePosition: ['window', 'document', ['querySelector', '#tswcomments']],237},238{239command: InteractionCommand.type,240keyboardCommands: [241{242string:243'In the depth of winter, I finally learned that within me there lay an invincible summer.',244},245],246},247]);248await tab.interact([249{250command: InteractionCommand.click,251mousePosition: ['window', 'document', ['querySelector', '#tswsubmit']],252},253]);254await tab.waitForMillis(1000);255256const { hasRecaptchaPopup } = await page.evaluate(`(() => {257const hasRecaptchaPopup = !!document.querySelectorAll('iframe[title="recaptcha challenge"]')258.length;259return { hasRecaptchaPopup };260})()`);261262await tab.close();263264expect(hasRecaptchaPopup).toBe(true);265});266267async function createPage(): Promise<IPuppetPage> {268const meta = await coreServerConnection.createSession();269const tab = Session.getTab(meta);270Helpers.needsClosing.push(tab.session);271await tab.goto(koaServer.baseUrl);272await tab.waitForLoad('PaintingStable');273return tab.puppetPage;274}275276277