content-script-spec.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { expect } from 'chai'
  2. import * as path from 'path'
  3. import { closeWindow } from './window-helpers'
  4. import { emittedNTimes } from './events-helpers'
  5. import { BrowserWindow, ipcMain, WebContents } from 'electron'
  6. describe('chrome extension content scripts', () => {
  7. const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures')
  8. const extensionPath = path.resolve(fixtures, 'extensions')
  9. const addExtension = (name: string) => BrowserWindow.addExtension(path.resolve(extensionPath, name))
  10. const removeAllExtensions = () => {
  11. Object.keys(BrowserWindow.getExtensions()).map(extName => {
  12. BrowserWindow.removeExtension(extName)
  13. })
  14. }
  15. let responseIdCounter = 0
  16. const executeJavaScriptInFrame = (webContents: WebContents, frameRoutingId: number, code: string) => {
  17. return new Promise(resolve => {
  18. const responseId = responseIdCounter++
  19. ipcMain.once(`executeJavaScriptInFrame_${responseId}`, (event, result) => {
  20. resolve(result)
  21. })
  22. webContents.send('executeJavaScriptInFrame', frameRoutingId, code, responseId)
  23. })
  24. }
  25. const generateTests = (sandboxEnabled: boolean, contextIsolationEnabled: boolean) => {
  26. describe(`with sandbox ${sandboxEnabled ? 'enabled' : 'disabled'} and context isolation ${contextIsolationEnabled ? 'enabled' : 'disabled'}`, () => {
  27. let w: BrowserWindow
  28. describe('supports "run_at" option', () => {
  29. beforeEach(async () => {
  30. await closeWindow(w)
  31. w = new BrowserWindow({
  32. show: false,
  33. width: 400,
  34. height: 400,
  35. webPreferences: {
  36. contextIsolation: contextIsolationEnabled,
  37. sandbox: sandboxEnabled
  38. }
  39. })
  40. })
  41. afterEach(() => {
  42. removeAllExtensions()
  43. return closeWindow(w).then(() => { w = null as unknown as BrowserWindow })
  44. })
  45. it('should run content script at document_start', () => {
  46. addExtension('content-script-document-start')
  47. w.webContents.once('dom-ready', async () => {
  48. const result = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor')
  49. expect(result).to.equal('red')
  50. })
  51. w.loadURL('about:blank')
  52. })
  53. it('should run content script at document_idle', async () => {
  54. addExtension('content-script-document-idle')
  55. w.loadURL('about:blank')
  56. const result = await w.webContents.executeJavaScript('document.body.style.backgroundColor')
  57. expect(result).to.equal('red')
  58. })
  59. it('should run content script at document_end', () => {
  60. addExtension('content-script-document-end')
  61. w.webContents.once('did-finish-load', async () => {
  62. const result = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor')
  63. expect(result).to.equal('red')
  64. })
  65. w.loadURL('about:blank')
  66. })
  67. })
  68. describe('supports "all_frames" option', () => {
  69. const contentScript = path.resolve(fixtures, 'extensions/content-script')
  70. // Computed style values
  71. const COLOR_RED = `rgb(255, 0, 0)`
  72. const COLOR_BLUE = `rgb(0, 0, 255)`
  73. const COLOR_TRANSPARENT = `rgba(0, 0, 0, 0)`
  74. before(() => {
  75. BrowserWindow.addExtension(contentScript)
  76. })
  77. after(() => {
  78. BrowserWindow.removeExtension('content-script-test')
  79. })
  80. beforeEach(() => {
  81. w = new BrowserWindow({
  82. show: false,
  83. webPreferences: {
  84. // enable content script injection in subframes
  85. nodeIntegrationInSubFrames: true,
  86. preload: path.join(contentScript, 'all_frames-preload.js')
  87. }
  88. })
  89. })
  90. afterEach(() =>
  91. closeWindow(w).then(() => {
  92. w = null as unknown as BrowserWindow
  93. })
  94. )
  95. it('applies matching rules in subframes', async () => {
  96. const detailsPromise = emittedNTimes(w.webContents, 'did-frame-finish-load', 2)
  97. w.loadFile(path.join(contentScript, 'frame-with-frame.html'))
  98. const frameEvents = await detailsPromise
  99. await Promise.all(
  100. frameEvents.map(async frameEvent => {
  101. const [, isMainFrame, , frameRoutingId] = frameEvent
  102. const result: any = await executeJavaScriptInFrame(
  103. w.webContents,
  104. frameRoutingId,
  105. `(() => {
  106. const a = document.getElementById('all_frames_enabled')
  107. const b = document.getElementById('all_frames_disabled')
  108. return {
  109. enabledColor: getComputedStyle(a).backgroundColor,
  110. disabledColor: getComputedStyle(b).backgroundColor
  111. }
  112. })()`
  113. )
  114. expect(result.enabledColor).to.equal(COLOR_RED)
  115. if (isMainFrame) {
  116. expect(result.disabledColor).to.equal(COLOR_BLUE)
  117. } else {
  118. expect(result.disabledColor).to.equal(COLOR_TRANSPARENT) // null color
  119. }
  120. })
  121. )
  122. })
  123. })
  124. })
  125. }
  126. generateTests(false, false)
  127. generateTests(false, true)
  128. generateTests(true, false)
  129. generateTests(true, true)
  130. })