Add smoke test script that runs in chrome headless.

This commit is contained in:
Guo Xiang Tan 2017-12-18 16:32:58 +08:00
parent b9f553d45d
commit 8d44642b97
4 changed files with 381 additions and 6 deletions

View File

@ -31,7 +31,15 @@ task "smoke:test" do
end
results = ""
IO.popen("#{phantom_path} #{Rails.root}/spec/phantom_js/smoke_test.js #{url}").each do |line|
command =
if ENV["USE_CHROME"]
"node #{Rails.root}/test/smoke_test.js #{url}"
else
"#{phantom_path} #{Rails.root}/spec/phantom_js/smoke_test.js #{url}"
end
IO.popen(command).each do |line|
puts line
results << line
end

View File

@ -8,6 +8,7 @@
"dependencies": {},
"devDependencies": {
"chrome-launcher": "^0.10.0",
"chrome-remote-interface": "^0.25.4"
"chrome-remote-interface": "^0.25.4",
"puppeteer": "^0.13.0"
}
}

235
test/smoke_test.js Normal file
View File

@ -0,0 +1,235 @@
const args = process.argv.slice(2);
if (args.length < 1 || args.length > 2) {
console.log("Expecting: node {smoke_test.js} {url}");
process.exit(1);
}
const url = args[0];
console.log(`Starting Discourse Smoke Test for ${url}`);
const puppeteer = require('puppeteer');
const path = require('path');
(async () => {
const browser = await puppeteer.launch({
// headless: false,
// slowMo: 10,
args: ["--disable-local-storage"]
});
const page = await browser.newPage();
page.setViewport = {
width: 1366,
height: 768
};
const exec = (description, fn, assertion) => {
const start = +new Date();
return fn.call().then(output => {
if (assertion) {
if (assertion.call(this, output)) {
console.log(`PASSED: ${description} - ${(+new Date()) - start}ms`);
} else {
console.log(`FAILED: ${description} - ${(+new Date()) - start}ms`);
console.log("SMOKE TEST FAILED");
process.exit(1);
}
} else {
console.log(`PASSED: ${description} - ${(+new Date()) - start}ms`);
}
}).catch(error => {
console.log(`ERROR (${description}): ${error.message} - ${(+new Date()) - start}ms`);
console.log("SMOKE TEST FAILED");
process.exit(1);
});
};
const assert = (description, fn, assertion) => {
return exec(description, fn, assertion);
};
page.on('console', msg => console.log(`PAGE LOG: ${msg.text}`));
await page.goto(url);
await exec("expect a log in button in the header", () => {
return page.waitForSelector("header .login-button", { timeout: 500, visible: true });
});
await exec("go to latest page", () => {
return page.goto(path.join(url, 'latest'), { timeout: 1500 });
});
await exec("at least one topic shows up", () => {
return page.waitForSelector(".topic-list tbody tr", { timeout: 500, visible: true });
});
await exec("go to categories page", () => {
return page.goto(path.join(url, 'categories'), { timeout: 1500 });
});
await exec("can see categories on the page", () => {
return page.waitForSelector(".category-list", { timeout: 500, visible: true });
});
await exec("navigate to 1st topic", () => {
return page.click(".main-link a.title:first-of-type", { timeout: 500 });
});
await exec("at least one post body", () => {
return page.waitForSelector(".topic-post", { timeout: 500, visible: true });
});
await exec("click on the 1st user", () => {
return page.click(".topic-meta-data a:first-of-type", { timeout: 500 });
});
await exec("user has details", () => {
return page.waitForSelector("#user-card .names", { timeout: 500, visible: true });
});
if (!process.env.READONLY_TESTS) {
await exec("open login modal", () => {
return page.click(".login-button", { timeout: 500 });
});
await exec("login modal is open", () => {
return page.waitForSelector(".login-modal", { timeout: 500, visible: true });
});
await exec("type in credentials & log in", () => {
let promise = page.type("#login-account-name", process.env.DISCOURSE_USERNAME || 'smoke_user');
promise = promise.then(() => {
return page.type("#login-account-password", process.env.DISCOURSE_PASSWORD || 'P4ssw0rd');
});
promise = promise.then(() => {
return page.click(".login-modal .btn-primary", { timeout: 500 });
});
return promise;
});
await exec("is logged in", () => {
return page.waitForSelector(".current-user", { timeout: 2000, visible: true });
});
await exec("go home", () => {
return page.click("#site-logo, #site-text-logo", { timeout: 500 });
});
await exec("it shows a topic list", () => {
return page.waitForSelector(".topic-list", { timeout: 1500, visible: true });
});
await exec("we have a create topic button", () => {
return page.waitForSelector("#create-topic", { timeout: 500, visible: true });
});
await exec("open composer", () => {
return page.click("#create-topic", { timeout: 500 });
});
await exec("the editor is visible", () => {
return page.waitForFunction(
"document.activeElement === document.getElementById('reply-title')",
{ timeout: 500 }
);
});
await exec("compose new topic", () => {
const date = `(${(+new Date())})`;
const title = `This is a new topic ${date}`;
const post = `I can write a new topic inside the smoke test! ${date} \n\n`;
let promise = page.type("#reply-title", title);
promise = promise.then(() => {
return page.type("#reply-control .d-editor-input", post);
});
return promise;
});
await exec("updates preview", () => {
return page.waitForSelector(".d-editor-preview p", { timeout: 500, visible: true });
});
await exec("open upload modal", () => {
return page.click(".d-editor-button-bar .upload", { timeout: 500 });
});
await exec("upload modal is open", () => {
let promise = page.waitForSelector("#filename-input", { timeout: 1500, visible: true });
promise.then(() => {
return page.click(".d-modal-cancel", { timeout: 500 });
});
return promise;
});
await exec("submit the topic", () => {
return page.click(".submit-panel .create", { timeout: 500 });
});
await exec("topic is created", () => {
return page.waitForSelector(".fancy-title", { timeout: 1500, visible: true });
});
await exec("open the composer", () => {
return page.click(".post-controls:first-of-type .create", { timeout: 500 });
});
await exec("composer is open", () => {
return page.waitForSelector("#reply-control .d-editor-input", { timeout: 500, visible: true });
});
await exec("compose reply", () => {
const post = `I can even write a reply inside the smoke test ;) (${(+new Date())})`;
return page.type("#reply-control .d-editor-input", post);
});
await assert("waiting for the preview", () => {
let promise = page.waitForSelector(".d-editor-preview p",
{ timeout: 500, visible: true }
);
promise = promise.then(() => {
return page.evaluate(() => {
return document.querySelector(".d-editor-preview").innerText;
});
});
return promise;
}, output => {
return output.match("I can even write a reply");
});
await exec("submit the topic", () => {
return page.click("#reply-control .create", { timeout: 6000 });
});
await assert("reply is created", () => {
let promise = page.waitForSelector(".topic-post", { timeout: 500 });
promise = promise.then(() => {
return page.evaluate(() => {
return document.querySelectorAll(".topic-post").length;
});
});
return promise;
}, output => {
return output === 2;
});
}
await browser.close();
console.log("ALL PASSED");
})();

139
yarn.lock
View File

@ -18,6 +18,12 @@
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
agent-base@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.2.tgz#80fa6cde440f4dcf9af2617cf246099b5d99f0c8"
dependencies:
es6-promisify "^5.0.0"
async-limiter@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
@ -61,12 +67,55 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
debug@^2.6.8:
concat-stream@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
dependencies:
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
debug@2.6.9, debug@^2.6.8:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
debug@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
es6-promise@^4.0.3:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a"
es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
dependencies:
es6-promise "^4.0.3"
extract-zip@^1.6.5:
version "1.6.6"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c"
dependencies:
concat-stream "1.6.0"
debug "2.6.9"
mkdirp "0.5.0"
yauzl "2.4.1"
fd-slicer@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
dependencies:
pend "~1.2.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -82,6 +131,13 @@ glob@^7.0.5:
once "^1.3.0"
path-is-absolute "^1.0.0"
https-proxy-agent@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz#a7ce4382a1ba8266ee848578778122d491260fd9"
dependencies:
agent-base "^4.1.0"
debug "^3.1.0"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -89,7 +145,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2:
inherits@2, inherits@^2.0.3, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
@ -97,12 +153,20 @@ is-wsl@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
lighthouse-logger@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.0.1.tgz#f073d83f7acbc96729bf100a121c8f006991ae61"
dependencies:
debug "^2.6.8"
mime@^1.3.4:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@ -113,6 +177,12 @@ minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
mkdirp@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
dependencies:
minimist "0.0.8"
mkdirp@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@ -133,28 +203,89 @@ path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
progress@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
proxy-from-env@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
puppeteer@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-0.13.0.tgz#2e6956205f2c640964c2107f620ae1eef8bde8fd"
dependencies:
debug "^2.6.8"
extract-zip "^1.6.5"
https-proxy-agent "^2.1.0"
mime "^1.3.4"
progress "^2.0.0"
proxy-from-env "^1.0.0"
rimraf "^2.6.1"
ws "^3.0.0"
readable-stream@^2.2.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
safe-buffer "~5.1.1"
string_decoder "~1.0.3"
util-deprecate "~1.0.1"
rimraf@^2.6.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
glob "^7.0.5"
safe-buffer@~5.1.0:
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
string_decoder@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
dependencies:
safe-buffer "~5.1.0"
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
ultron@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
ws@3.3.x:
ws@3.3.x, ws@^3.0.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.2.tgz#96c1d08b3fefda1d5c1e33700d3bfaa9be2d5608"
dependencies:
async-limiter "~1.0.0"
safe-buffer "~5.1.0"
ultron "~1.1.0"
yauzl@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
dependencies:
fd-slicer "~1.0.1"