Вход в Google с помощью Playwright в среде CI - PullRequest
0 голосов
/ 24 февраля 2020

У меня есть сценарий драматурга / мокко, который регистрирует меня в Google. Этот код работает при запуске на моем локальном компьютере, но не работает при запуске в gitlab-ci.

e2e.spec.js

describe('Staging', async function() {
  before(async function() {
    await playwright.selectors.register(selectorEngine, { name: 'shadow' });
    browser = await playwright.chromium.launch({
      args: [
        '--disable-web-security',
        '--disable-features=IsolateOrigins,site-per-process',
      ],
    });

    context = await browser.newContext({
      geolocation: { latitude: 40.0583, longitude: 74.4057 },
      viewport: playwright.devices['Pixel 2'].viewport,
    });

    page = await context.newPage();
    await page.addScriptTag({ content: `./headless-spoof.js` });
  });

  afterEach(async function() {
    await page.screenshot({ path: `screenshots/${screenshotcounter++} - ${this.currentTest.title.replace(/\s+/g, '_')}.png` });
  });

  after(async function() {
    await page.close();
    await context.close();
    await browser.close();
  });

  describe('Signing In, Joining, and Cancelling', function() {
    before(goto('/subscribe?plan=gold'));

    it('Logs in with Google', async function() {
      // Click the "Sign in with Google" Button
      const selector = 'shadow=[data-provider-id="google.com"]';
      await page.waitForSelector(selector, { visibility: 'visible' });
      const login = await page.$(selector);
      await login.click();

      await page.waitForNavigation();
      await new Promise(r => setTimeout(r, 5 * 1000));

      // Disambiguate: Which version of the Google sign-in form is it?
      const content = await page.evaluate(body => body.innerHTML, await page.$('body'));
      const isMobileLoginPage = content.includes('One account. All of Google.');

      // Fill Username
      const userNameSelector = isMobileLoginPage ? '#Email' : '#identifierId';
      await page.waitForSelector(userNameSelector, { visibility: 'visible' });
      const userNameField = await page.$(userNameSelector);
      await userNameField.fill(process.env.GMAIL_USER);
      await userNameField.press('Enter');

      // Fill Password
      const passwordSelector = isMobileLoginPage ? '#Passwd' : 'input[type="password"]';
      await page.waitForSelector(passwordSelector, { visibility: 'visible' });
      const passwordField = await page.$(passwordSelector);
      await passwordField.fill(process.env.GMAIL_PASS);
      await passwordField.press('Enter');

      await page.waitForNavigation();

      // Meanwhile, back at the ranch...
      const subscribeSelector = 'shadow=#payment h2';
      await page.waitForSelector(subscribeSelector, { visibility: 'visible' });

      const heading = await page.$eval(subscribeSelector, textContent);
      expect(heading).to.match(/Secure Payment/);
    });
  });
});

headless-spoof.js

// overwrite the `languages` property to use a custom getter
Object.defineProperty(window.navigator, 'languages', {
  get: function() {
    return ['en-US', 'en'];
  },
});

// overwrite the `plugins` property to use a custom getter
Object.defineProperty(window.navigator, 'plugins', {
  get: function() {
    // this just needs to have `length > 0`, but we could mock the plugins too
    return [1, 2, 3, 4, 5];
  },
});

const { getParameter } = WebGLRenderingContext;
WebGLRenderingContext.prototype.getParameter = function(parameter) {
  // UNMASKED_VENDOR_WEBGL
  if (parameter === 37445)
    return 'Intel Open Source Technology Center';

  // UNMASKED_RENDERER_WEBGL
  if (parameter === 37446)
    return 'Mesa DRI Intel(R) Ivybridge Mobile ';


  return getParameter(parameter);
};

['height', 'width'].forEach(property => {
  // store the existing descriptor
  const imageDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, property);

  // redefine the property with a patched descriptor
  Object.defineProperty(HTMLImageElement.prototype, property, {
    ...imageDescriptor,
    get: function() {
      // return an arbitrary non-zero dimension if the image failed to load
      if (this.complete && this.naturalHeight == 0)
        return 20;

      // otherwise, return the actual dimension
      return imageDescriptor.get.apply(this);
    },
  });
});

// store the existing descriptor
const elementDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight');

// redefine the property with a patched descriptor
Object.defineProperty(HTMLDivElement.prototype, 'offsetHeight', {
  ...elementDescriptor,
  get: function() {
    if (this.id === 'modernizr')
      return 1;

    return elementDescriptor.get.apply(this);
  },
});
e2e:chrome:
  image: arjun27/playwright-bionic:0.2.0
  environment: staging
  stage: e2e
  only:
    - development
  script:
    - mkdir -p screenshots
    - npx mocha -r dotenv/config 'test/*.spec.js' --bail --timeout 15000
  artifacts:
    paths:
    - screenshots
    expire_in: 1 week
    when: always

Несмотря на эти меры предосторожности, я все еще вижу этот результат в артефактах моей работы CI:

Могу ли я что-нибудь сделать в моих тестовых сценариях или с соответствующей учетной записью Google, чтобы преодолеть это препятствие?

...