angular / protractor

E2E test framework for Angular apps
http://www.protractortest.org
MIT License
8.75k stars 2.31k forks source link

Browser logs empty in afterEach, exists in end of test #5168

Open JonWallsten opened 5 years ago

JonWallsten commented 5 years ago

Bug Report

We're trying to store the browser log after each test case, but when we try to access the log in the afterEach hook the log is already emptied. It just returns an empty array. When fetching the log in the end of the test case though, it returns the messages. So there seems to be a race condition or something. Unfortunately I don't have the knowledge to deduct if the error is in Protractor, Selenium, Chrome Headless or Chromedriver. Maybe someone here has that knowledge?

Edit: I added a breakpoint in the Logs.get method in selenium webdriver. Entries are indeed empty when I try to collect the logs in the afterEach-hook.

  get(type) {
    let cmd = new command.Command(command.Name.GET_LOG).
        setParameter('type', type);
    return this.driver_.schedule(
        cmd, 'WebDriver.manage().logs().get(' + type + ')').
        then(function(entries) {
          return entries.map(function(entry) {
            if (!(entry instanceof logging.Entry)) {
              return new logging.Entry(
                  entry['level'], entry['message'], entry['timestamp'],
                  entry['type']);
            }
            return entry;
          });
        });
  }

let puppeteer = null; if(process.env.HEADLESS) { puppeteer = require('puppeteer'); }

const consoleReporter = new JasmineConsoleReporter({ colors: process.env.IS_DEV ? 1 : 0, cleanStack: 1, verbosity: 4, listStyle: 'indent', activity: false });

const screenshotReporter = new HtmlScreenshotReporter({ dest: helpers.htmlReportDir, filename: 'test-report.html', reportOnlyFailedSpecs: false, captureOnlyFailedSpecs: true });

const junitReporter = new jasmineReporters.JUnitXmlReporter({ savePath: helpers.junitReportDir, consolidateAll: false });

exports.config = { framework: 'jasmine', chromeDriver: chromeDriverPath, multiCapabilities: [{ browserName: 'chrome', chromeOptions: { args: process.env.HEADLESS && puppeteer ? ['--headless', '--disable-gpu', '--no-sandbox', '--disable-extensions', '--disable-dev-shm-usage', '--window-size=1920,1200', '--disable-setuid-sandbox', '--auth-server-whitelist=*scania.com'] : [], binary: process.env.HEADLESS && puppeteer ? puppeteer.executablePath() : undefined } }], getPageTimeout: 90000, // How long to wait for a page to load allScriptsTimeout: 90000, // The timeout in milliseconds for each script run on the browser. This should be longer than the maximum time your application needs to stabilize between tasks.

plugins: [
    {
        package: 'jasmine2-protractor-utils',
        disableHTMLReport: true,
        disableScreenshot: false,
        screenshotOnExpectFailure: true,
        screenshotOnSpecFailure: false,
        screenshotPath: '.test_results/html_report',
        clearFoldersBeforeTest: true,
        htmlReportDir:  '.test_results/html_report',
        failTestOnErrorLog: {
            failTestOnErrorLogLevel: 2000
        }
    }
],

suites: {
    smoke: './test/e2e/**/*.e2e-spec.ts',
    full: [
        // './test/e2e/**/*.e2e-spec.ts',
        './test/e2e/*.e2e-spec.ts'
        ]
},
// Default suite
suite: 'full',

directConnect: true,

jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 220000   // Default time to wait in ms before a test fails.
},
onPrepare: () => {
    'use strict';

    if (!process.env.HEADLESS) {
        browser.driver.manage().window().maximize();
    }

    // Clean log file
    fs.writeFileSync(helpers.testResultDir + 'browser_output.log', '');

    jasmine.getEnv().addReporter(addSpecNameToBrowserLog);
    jasmine.getEnv().addReporter(junitReporter);
    jasmine.getEnv().addReporter(consoleReporter);
    jasmine.getEnv().addReporter(screenshotReporter);

    const testDataFiles = [['CO_structure.xml', 'CO_Test_Structure.txt']];

    const createTestDataAsync = async () => {
        await testDataFiles.reduce( async (previousPromise, paths) => {
            await previousPromise;
            return createTestdata.restCall(paths[0], paths[1]);
        }, Promise.resolve());
    };

    return createTestDataAsync();
},
afterLaunch: (exitCode) => {
    'use strict';

    return new Promise((resolve) => {
        screenshotReporter.afterLaunch(resolve.bind(this, exitCode));
    });
}

};

const addSpecNameToBrowserLog = { specStarted: (result) => { 'use strict'; fs.appendFileSync(helpers.testResultDir + 'browser_output.log', #${result.description} ${nodeOS.EOL}); } };

- A relevant example test

import { browser } from 'protractor';

describe('Tests', () => {

afterEach(() => {
    browser.manage().logs().get('browser').then((browserLog) => {
        console.log(browserLog); // Outputs: []
    });
});

it('Test anything', () => {
    // Test anything that causes a warning or error in the browser

    browser.manage().logs().get('browser').then((browserLog) => {
        console.log(browserLog); // Outputs log
    });
});

});

macroking commented 5 years ago

Looking at your sample test, it is working as expected only. Every time you call browser logs, after fetching the array will be empty only. You are fetching the log from the browser inside your test. It fetches all the log messages. When you call the browser logs again it will be null.

JonWallsten commented 5 years ago

But if I remove the code inside the test case it's still empty in the afterEach hook. And besides they both give me a result in chrome if I'm not running headless. So I think you're wrong.