We are building an Ionic hybrid app, and we implemented automated E2E tests that run by the CI system. All these test have been working properly until we implemented APP_INITIALIZE in our "app.module" to obtain the browser language before initialization.
This is a dirty code of our APP_INITIALIZE implementation:
-app.module.ts
export function configurateLocaleData(dynamicRegisterLocaleService: DynamicRegisterLocaleService): () => Promise<any> {
return () => dynamicRegisterLocaleService.configurateLocaleData();
}
...
providers: [
...
{
provide: APP_INITIALIZER,
useFactory: configurateLocaleData,
deps: [ DynamicRegisterLocaleService ],
multi: true
}
...
-dynamic-register-locale.service.ts
import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {AppConfig} from "../app.constants";
import {DateLocaleService} from "./dateLocale.service";
import {registerLocaleData} from "@angular/common";
@Injectable()
export class DynamicRegisterLocaleService {
constructor(private httpClient: HttpClient) {
}
public configurateLocaleData(): Promise<any> {
let currentLang = DateLocaleService.getLanguage();
return this.httpClient.get("../assets/locales/" + currentLang + ".js", {responseType: "text"}).toPromise()
.then(data => {
const startPos = data.indexOf(AppConfig.EXPORT_DEFAULT);
let localeText = "return " + data.substring(startPos + AppConfig.EXPORT_DEFAULT.length);
registerLocaleData((new Function(localeText))());
});
}
}
These are some of the protractor-cucumber tests we are running, and it's configuration:
-cucumber.conf.js
exports.config = {
allScriptsTimeout: 70000,
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
directConnect: true,
restartBrowserBetweenTests: true,
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
'args': ['--disable-web-security', '--headless', '--disable-gpu', '--no-sandbox'],
'perfLoggingPrefs': {
'enableNetwork': true,
'enablePage': false
}
},
loggingPrefs: {
performance: 'ALL',
browser: 'ALL'
}
},
specs: [
'../e2e/cucumber/features/*.feature'
],
cucumberOpts: {
require: ['../e2e/cucumber/steps/*.steps.js'],
strict: true
},
};
-cucumber.steps.js
var TestsCfg = require("./../tests.constants.js");
var SupportFunctions = require("./../support/support-functions.js");
var {defineSupportCode, After} = require("cucumber");
var chai = require("chai").use(require("chai-as-promised"));
var expect = chai.expect;
defineSupportCode(function({setDefaultTimeout, When, Then, Given, And}) {
setDefaultTimeout(TestsCfg.CUCUMBER_STEPS_MAX_TIMEOUT_MS);
After(function() {
return browser.manage().logs().get('browser').then(function(browserLogs) {
console.log("Console logs for this scenario: ");
browserLogs.forEach(function(log){
console.log(log.message);
});
});
});
When("I navigate to App", function() {
return browser.get(TestsCfg.APP_TEST_URL);
});
Then("the title should be {string}", function(title) {
return expect(browser.getTitle()).to.eventually.eql(title);
});
Given("I should be able to login as {string}", function(username) {
var usernameInput = element.all(by.css(".login-input .text-input")).get(0).getWebElement();
var passwordInput = element.all(by.css(".login-input .text-input")).get(1).getWebElement();
var loginButton = element(by.id("loginButton"));
return browser.wait(SupportFunctions.isElementVisible(loginButton)).then(function() {
usernameInput.click();
usernameInput.sendKeys(username);
passwordInput.click();
passwordInput.sendKeys(pass);
return loginButton.click();
});
});
Then("the dashboard should be shown for house {string}", function(house) {
var headerSpan = element(by.css(".header-text"));
return browser.wait(SupportFunctions.isElementVisible(headerSpan)).then(function() {
return expect(headerSpan.getText()).to.eventually.eql(house);
});
});
There are more tests, but all of them work the same way. We go to the desired URL, we log in and then run a specific test. As it's an Ionic app, they all have ExpectedConditions so it wait until everything is properly loaded.
The problem is, all these test runs properly locally, and, before implementing APP_INITIALIZE, they also worked in our CI system. As soon as APP_INITIALIZE was implemented, these errors started appearing for every single test:
Our CI is Bitbucket Pipelines, running a Docker image weboaks/node-karma-protractor-chrome:debian-node8
, which includes a Chromium version 64.0.3282.119. We use chromedriver 2.37 which is the latest version compatible with Chromium 64.
And these are the facts we got from out tests:
- We know it's related to APP_INITIALIZE because if we erase that implementation everything works properly.
- We also know that it works fine when running Protractor-Cucumber without the
"--headless"
flag. - It works too when using a Chromium v66, even headless. But it doesn't work on Chromium 64.0.3282.119.
Does anyone know if this is an Angular, Protractor or Chromium bug?
Thanks!