<commit_before>import { expect } from 'chai';
import { app, session, BrowserWindow, ipcMain, WebContents, Extension, Session } from 'electron/main';
import { closeAllWindows, closeWindow } from './window-helpers';
import * as http from 'http';
import { AddressInfo } from 'net';
import * as path from 'path';
import * as fs from 'fs';
import * as WebSocket from 'ws';
import { emittedOnce, emittedNTimes } from './events-helpers';

const uuid = require('uuid');

const fixtures = path.join(__dirname, 'fixtures');

describe('chrome extensions', () => {
  const emptyPage = '<script>console.log("loaded")</script>';

  // NB. extensions are only allowed on http://, https:// and ftp:// (!) urls by default.
  let server: http.Server;
  let url: string;
  let port: string;
  before(async () => {
    server = http.createServer((req, res) => {
      if (req.url === '/cors') {
        res.setHeader('Access-Control-Allow-Origin', 'http://example.com');
      }
      res.end(emptyPage);
    });

    const wss = new WebSocket.Server({ noServer: true });
    wss.on('connection', function connection (ws) {
      ws.on('message', function incoming (message) {
        if (message === 'foo') {
          ws.send('bar');
        }
      });
    });

    await new Promise<void>(resolve => server.listen(0, '127.0.0.1', () => {
      port = String((server.address() as AddressInfo).port);
      url = `http://127.0.0.1:${port}`;
      resolve();
    }));
  });
  after(() => {
    server.close();
  });
  afterEach(closeAllWindows);
  afterEach(() => {
    session.defaultSession.getAllExtensions().forEach((e: any) => {
      session.defaultSession.removeExtension(e.id);
    });
  });

  it('does not crash when using chrome.management', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
    await w.loadURL('about:blank');

    await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
    const args: any = await emittedOnce(app, 'web-contents-created');
    const wc: Electron.WebContents = args[1];
    await expect(wc.executeJavaScript(`
      (() => {
        return new Promise((resolve) => {
          chrome.management.getSelf((info) => {
            resolve(info);
          });
        })
      })();
    `)).to.eventually.have.property('id');
  });

  it('can open WebSQLDatabase in a background page', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
    await w.loadURL('about:blank');

    await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
    const args: any = await emittedOnce(app, 'web-contents-created');
    const wc: Electron.WebContents = args[1];
    await expect(wc.executeJavaScript('(()=>{try{openDatabase("t", "1.0", "test", 2e5);return true;}catch(e){throw e}})()')).to.not.be.rejected();
  });

  function fetch (contents: WebContents, url: string) {
    return contents.executeJavaScript(`fetch(${JSON.stringify(url)})`);
  }

  it('bypasses CORS in requests made from extensions', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
    const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
    await w.loadURL(`${extension.url}bare-page.html`);
    await expect(fetch(w.webContents, `${url}/cors`)).to.not.be.rejectedWith(TypeError);
  });

  it('loads an extension', async () => {
    // NB. we have to use a persist: session (i.e. non-OTR) because the
    // extension registry is redirected to the main session. so installing an
    // extension in an in-memory session results in it being installed in the
    // default session.
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
    await w.loadURL(url);
    const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
    expect(bg).to.equal('red');
  });

  it('does not crash when failing to load an extension', async () => {
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    const promise = customSession.loadExtension(path.join(fixtures, 'extensions', 'load-error'));
    await expect(promise).to.eventually.be.rejected();
  });

  it('serializes a loaded extension', async () => {
    const extensionPath = path.join(fixtures, 'extensions', 'red-bg');
    const manifest = JSON.parse(fs.readFileSync(path.join(extensionPath, 'manifest.json'), 'utf-8'));
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    const extension = await customSession.loadExtension(extensionPath);
    expect(extension.id).to.be.a('string');
    expect(extension.name).to.be.a('string');
    expect(extension.path).to.be.a('string');
    expect(extension.version).to.be.a('string');
    expect(extension.url).to.be.a('string');
    expect(extension.manifest).to.deep.equal(manifest);
  });

  it('removes an extension', async () => {
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
    {
      const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
      await w.loadURL(url);
      const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
      expect(bg).to.equal('red');
    }
    customSession.removeExtension(id);
    {
      const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
      await w.loadURL(url);
      const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
      expect(bg).to.equal('');
    }
  });

  it('emits extension lifecycle events', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);

    const loadedPromise = emittedOnce(customSession, 'extension-loaded');
    const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
    const [, loadedExtension] = await loadedPromise;
    const [, readyExtension] = await emittedOnce(customSession, 'extension-ready');

    // Compare JSON string to print more information if failed.
    const expected = JSON.stringify(extension);
    expect(JSON.stringify(loadedExtension)).to.equal(expected);
    expect(JSON.stringify(readyExtension)).to.equal(expected);
<commit_msg>test: ignore the ready event from PDF Viewer (#28039)<commit_after>import { expect } from 'chai';
import { app, session, BrowserWindow, ipcMain, WebContents, Extension, Session } from 'electron/main';
import { closeAllWindows, closeWindow } from './window-helpers';
import * as http from 'http';
import { AddressInfo } from 'net';
import * as path from 'path';
import * as fs from 'fs';
import * as WebSocket from 'ws';
import { emittedOnce, emittedNTimes, emittedUntil } from './events-helpers';

const uuid = require('uuid');

const fixtures = path.join(__dirname, 'fixtures');

describe('chrome extensions', () => {
  const emptyPage = '<script>console.log("loaded")</script>';

  // NB. extensions are only allowed on http://, https:// and ftp:// (!) urls by default.
  let server: http.Server;
  let url: string;
  let port: string;
  before(async () => {
    server = http.createServer((req, res) => {
      if (req.url === '/cors') {
        res.setHeader('Access-Control-Allow-Origin', 'http://example.com');
      }
      res.end(emptyPage);
    });

    const wss = new WebSocket.Server({ noServer: true });
    wss.on('connection', function connection (ws) {
      ws.on('message', function incoming (message) {
        if (message === 'foo') {
          ws.send('bar');
        }
      });
    });

    await new Promise<void>(resolve => server.listen(0, '127.0.0.1', () => {
      port = String((server.address() as AddressInfo).port);
      url = `http://127.0.0.1:${port}`;
      resolve();
    }));
  });
  after(() => {
    server.close();
  });
  afterEach(closeAllWindows);
  afterEach(() => {
    session.defaultSession.getAllExtensions().forEach((e: any) => {
      session.defaultSession.removeExtension(e.id);
    });
  });

  it('does not crash when using chrome.management', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
    await w.loadURL('about:blank');

    await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
    const args: any = await emittedOnce(app, 'web-contents-created');
    const wc: Electron.WebContents = args[1];
    await expect(wc.executeJavaScript(`
      (() => {
        return new Promise((resolve) => {
          chrome.management.getSelf((info) => {
            resolve(info);
          });
        })
      })();
    `)).to.eventually.have.property('id');
  });

  it('can open WebSQLDatabase in a background page', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
    await w.loadURL('about:blank');

    await customSession.loadExtension(path.join(fixtures, 'extensions', 'persistent-background-page'));
    const args: any = await emittedOnce(app, 'web-contents-created');
    const wc: Electron.WebContents = args[1];
    await expect(wc.executeJavaScript('(()=>{try{openDatabase("t", "1.0", "test", 2e5);return true;}catch(e){throw e}})()')).to.not.be.rejected();
  });

  function fetch (contents: WebContents, url: string) {
    return contents.executeJavaScript(`fetch(${JSON.stringify(url)})`);
  }

  it('bypasses CORS in requests made from extensions', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession, sandbox: true } });
    const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'ui-page'));
    await w.loadURL(`${extension.url}bare-page.html`);
    await expect(fetch(w.webContents, `${url}/cors`)).to.not.be.rejectedWith(TypeError);
  });

  it('loads an extension', async () => {
    // NB. we have to use a persist: session (i.e. non-OTR) because the
    // extension registry is redirected to the main session. so installing an
    // extension in an in-memory session results in it being installed in the
    // default session.
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
    const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
    await w.loadURL(url);
    const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
    expect(bg).to.equal('red');
  });

  it('does not crash when failing to load an extension', async () => {
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    const promise = customSession.loadExtension(path.join(fixtures, 'extensions', 'load-error'));
    await expect(promise).to.eventually.be.rejected();
  });

  it('serializes a loaded extension', async () => {
    const extensionPath = path.join(fixtures, 'extensions', 'red-bg');
    const manifest = JSON.parse(fs.readFileSync(path.join(extensionPath, 'manifest.json'), 'utf-8'));
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    const extension = await customSession.loadExtension(extensionPath);
    expect(extension.id).to.be.a('string');
    expect(extension.name).to.be.a('string');
    expect(extension.path).to.be.a('string');
    expect(extension.version).to.be.a('string');
    expect(extension.url).to.be.a('string');
    expect(extension.manifest).to.deep.equal(manifest);
  });

  it('removes an extension', async () => {
    const customSession = session.fromPartition(`persist:${uuid.v4()}`);
    const { id } = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
    {
      const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
      await w.loadURL(url);
      const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
      expect(bg).to.equal('red');
    }
    customSession.removeExtension(id);
    {
      const w = new BrowserWindow({ show: false, webPreferences: { session: customSession } });
      await w.loadURL(url);
      const bg = await w.webContents.executeJavaScript('document.documentElement.style.backgroundColor');
      expect(bg).to.equal('');
    }
  });

  it('emits extension lifecycle events', async () => {
    const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);

    const loadedPromise = emittedOnce(customSession, 'extension-loaded');
    const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
    const [, loadedExtension] = await loadedPromise;
    const [, readyExtension] = await emittedUntil(customSession, 'extension-ready', (event: Event, extension: Extension) => {
      return extension.name !== 'Chromium PDF Viewer';
    });

    // Compare JSON string to print more information if failed.
    const expected = JSON.stringify(extension);
    expect(JSON.stringify(loadedExtension)).to.equal(expected);
    expect(JSON.stringify(readyExtension)).to.equal(expected);

{'fraction_non_alphanumeric': 0.16734028220945898, 'fraction_numerical': 0.0043253208537190665, 'mean_word_length': 4.0085227272727275, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 50, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5422115', 'n_tokens_mistral': 4175, 'n_tokens_neox': 4112, 'n_words': 936}