mirror of
https://gitlab.com/timvisee/send.git
synced 2024-11-10 21:22:35 +01:00
Merge pull request #960 from mozilla/vnext-integration-tests
Vnext integration tests
This commit is contained in:
commit
23932c0d4c
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ ios/send-ios/assets/ios.js
|
|||||||
ios/send-ios/assets/vendor.js
|
ios/send-ios/assets/vendor.js
|
||||||
ios/send-ios.xcodeproj/project.xcworkspace/xcuserdata/*
|
ios/send-ios.xcodeproj/project.xcworkspace/xcuserdata/*
|
||||||
ios/send-ios.xcodeproj/xcuserdata/*
|
ios/send-ios.xcodeproj/xcuserdata/*
|
||||||
|
test/integration/downloads
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
# autogenerated pyup.io config file
|
|
||||||
# see https://pyup.io/docs/configuration/ for all available options
|
|
||||||
|
|
||||||
schedule: every week
|
|
||||||
requirements:
|
|
||||||
- test/integration/Pipfile
|
|
||||||
- test/integration/pipenv.txt
|
|
44
circle.yml
44
circle.yml
@ -6,10 +6,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: send-{{ checksum "package-lock.json" }}
|
key: send-build-{{ checksum "package-lock.json" }}
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: send-{{ checksum "package-lock.json" }}
|
key: send-build-{{ checksum "package-lock.json" }}
|
||||||
paths:
|
paths:
|
||||||
- node_modules
|
- node_modules
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
@ -23,10 +23,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: send-{{ checksum "package-lock.json" }}
|
key: send-test-{{ checksum "package-lock.json" }}
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: send-{{ checksum "package-lock.json" }}
|
key: send-test-{{ checksum "package-lock.json" }}
|
||||||
paths:
|
paths:
|
||||||
- node_modules
|
- node_modules
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
@ -34,21 +34,19 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: coverage
|
path: coverage
|
||||||
integration_tests:
|
integration_tests:
|
||||||
machine: true
|
docker:
|
||||||
|
- image: circleci/node:10
|
||||||
|
- image: selenium/standalone-firefox
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- restore_cache:
|
||||||
at: .
|
key: send-int-{{ checksum "package-lock.json" }}
|
||||||
- run:
|
- run: npm install
|
||||||
name: Install Docker Compose
|
- save_cache:
|
||||||
command: |
|
key: send-int-{{ checksum "package-lock.json" }}
|
||||||
set -x
|
paths:
|
||||||
pip install docker-compose>=1.18
|
- node_modules
|
||||||
docker-compose --version
|
- run: npm run circleci-test-integration
|
||||||
- run:
|
|
||||||
command: npm run test-integration
|
|
||||||
- store_artifacts:
|
|
||||||
path: coverage/send-test.html
|
|
||||||
deploy_dev:
|
deploy_dev:
|
||||||
machine: true
|
machine: true
|
||||||
steps:
|
steps:
|
||||||
@ -92,12 +90,12 @@ workflows:
|
|||||||
ignore:
|
ignore:
|
||||||
- master
|
- master
|
||||||
- vnext
|
- vnext
|
||||||
# - integration_tests:
|
- integration_tests:
|
||||||
# filters:
|
filters:
|
||||||
# branches:
|
branches:
|
||||||
# ignore: master
|
ignore: master
|
||||||
# requires:
|
requires:
|
||||||
# - build
|
- build
|
||||||
build_and_deploy_dev:
|
build_and_deploy_dev:
|
||||||
jobs:
|
jobs:
|
||||||
- build:
|
- build:
|
||||||
|
@ -10,17 +10,10 @@ services:
|
|||||||
- REDIS_HOST=redis
|
- REDIS_HOST=redis
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
selenium:
|
selenium-firefox:
|
||||||
image: b4handjr/selenium-firefox
|
image: b4handjr/selenium-firefox
|
||||||
ports:
|
ports:
|
||||||
- "${VNC_PORT:-5900}:5900"
|
- "${VNC_PORT:-5900}:5900"
|
||||||
shm_size: 2g
|
shm_size: 2g
|
||||||
integration-tests:
|
|
||||||
build: ./test/integration
|
|
||||||
environment:
|
|
||||||
- BASE_URL=${BASE_URL:-http://web:1443}
|
|
||||||
links:
|
|
||||||
- web
|
|
||||||
- selenium
|
|
||||||
volumes:
|
volumes:
|
||||||
- "./coverage:/coverage"
|
- .:/code
|
||||||
|
13359
package-lock.json
generated
13359
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -22,10 +22,11 @@
|
|||||||
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
|
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
|
||||||
"release": "npm-run-all contributors changelog",
|
"release": "npm-run-all contributors changelog",
|
||||||
"test": "npm-run-all test:*",
|
"test": "npm-run-all test:*",
|
||||||
"test:backend": "nyc mocha --reporter=min test/backend",
|
"test:backend": "nyc --reporter=lcovonly mocha --reporter=min test/backend",
|
||||||
"test:frontend": "cross-env NODE_ENV=development node test/frontend/runner.js && nyc report --reporter=html",
|
"test:frontend": "cross-env NODE_ENV=development node test/frontend/runner.js",
|
||||||
"test-integration": "docker-compose up --abort-on-container-exit --exit-code-from integration-tests --build --remove-orphans --quiet-pull && docker-compose down",
|
"test:report": "nyc report --reporter=html",
|
||||||
"test-integration-stage": "cross-env BASE_URL=https://send.stage.mozaws.net npm run test-integration",
|
"test-integration": "cross-env NODE_ENV=development wdio test/wdio.docker.conf.js",
|
||||||
|
"circleci-test-integration": "cross-env NODE_ENV=development wdio test/wdio.circleci.conf.js",
|
||||||
"start": "npm run clean && cross-env NODE_ENV=development FXA_CLIENT_ID=fced6b5e3f4c66b9 BASE_URL=http://localhost:8080 webpack-dev-server --mode=development",
|
"start": "npm run clean && cross-env NODE_ENV=development FXA_CLIENT_ID=fced6b5e3f4c66b9 BASE_URL=http://localhost:8080 webpack-dev-server --mode=development",
|
||||||
"android": "cross-env ANDROID=1 npm start",
|
"android": "cross-env ANDROID=1 npm start",
|
||||||
"prod": "node server/bin/prod.js"
|
"prod": "node server/bin/prod.js"
|
||||||
@ -115,6 +116,13 @@
|
|||||||
"svgo-loader": "^2.2.0",
|
"svgo-loader": "^2.2.0",
|
||||||
"testpilot-ga": "^0.3.0",
|
"testpilot-ga": "^0.3.0",
|
||||||
"val-loader": "^1.1.1",
|
"val-loader": "^1.1.1",
|
||||||
|
"wdio-docker-service": "^1.4.2",
|
||||||
|
"wdio-dot-reporter": "0.0.10",
|
||||||
|
"wdio-firefox-profile-service": "^0.1.3",
|
||||||
|
"wdio-mocha-framework": "^0.6.3",
|
||||||
|
"wdio-sauce-service": "^0.4.11",
|
||||||
|
"wdio-spec-reporter": "^0.1.5",
|
||||||
|
"webdriverio": "^4.13.2",
|
||||||
"webpack": "^4.20.2",
|
"webpack": "^4.20.2",
|
||||||
"webpack-cli": "^3.1.2",
|
"webpack-cli": "^3.1.2",
|
||||||
"webpack-dev-middleware": "^3.4.0",
|
"webpack-dev-middleware": "^3.4.0",
|
||||||
|
@ -25,7 +25,8 @@ module.exports = function(app) {
|
|||||||
Object.setPrototypeOf(Combo.prototype, reporters.HTML.prototype)
|
Object.setPrototypeOf(Combo.prototype, reporters.HTML.prototype)
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
reporter: Combo
|
reporter: Combo,
|
||||||
|
timeout: 5000
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<script src="/jsconfig.js"></script>
|
<script src="/jsconfig.js"></script>
|
||||||
@ -37,8 +38,7 @@ module.exports = function(app) {
|
|||||||
<body>
|
<body>
|
||||||
<div id="mocha"></div>
|
<div id="mocha"></div>
|
||||||
<script>
|
<script>
|
||||||
mocha.checkLeaks();
|
window.runner = mocha.run();
|
||||||
const runner = mocha.run();
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
FROM ubuntu:xenial
|
|
||||||
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y python-pip python-dev && \
|
|
||||||
pip install tox
|
|
||||||
COPY . /integration
|
|
||||||
WORKDIR /integration
|
|
||||||
RUN tox --notest
|
|
||||||
|
|
||||||
CMD ["tox", "-e", "integration-tests"]
|
|
@ -1,76 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
"""Configuration files for pytest."""
|
|
||||||
import pytest
|
|
||||||
import requests
|
|
||||||
from requests.adapters import HTTPAdapter
|
|
||||||
from requests.packages.urllib3.util.retry import Retry
|
|
||||||
|
|
||||||
from pages.desktop.download import Download
|
|
||||||
from pages.desktop.home import Home
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def firefox_options(firefox_options, download_location_dir):
|
|
||||||
"""Firefox options."""
|
|
||||||
firefox_options.set_preference("browser.download.panel.shown", False)
|
|
||||||
firefox_options.set_preference(
|
|
||||||
"browser.helperApps.neverAsk.openFile", "text/plain")
|
|
||||||
firefox_options.set_preference(
|
|
||||||
"browser.helperApps.neverAsk.saveToDisk", "text/plain")
|
|
||||||
firefox_options.set_preference("browser.download.folderList", 2)
|
|
||||||
firefox_options.set_preference(
|
|
||||||
"browser.download.dir", "{0}".format(download_location_dir))
|
|
||||||
firefox_options.add_argument('-foreground')
|
|
||||||
firefox_options.log.level = 'trace'
|
|
||||||
return firefox_options
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session', autouse=True)
|
|
||||||
def _verify_url(request, base_url):
|
|
||||||
"""Verifies the base URL"""
|
|
||||||
verify = request.config.option.verify_base_url
|
|
||||||
if base_url and verify:
|
|
||||||
session = requests.Session()
|
|
||||||
retries = Retry(backoff_factor=0.1,
|
|
||||||
status_forcelist=[500, 502, 503, 504])
|
|
||||||
session.mount(base_url, HTTPAdapter(max_retries=retries))
|
|
||||||
session.get(base_url, verify=False)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def download_location_dir(tmpdir):
|
|
||||||
"""Directory for downloading sample file."""
|
|
||||||
return tmpdir.mkdir('test_download')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def upload_location_dir(tmpdir):
|
|
||||||
"""Directory for uploading sample file."""
|
|
||||||
return tmpdir.mkdir('test_upload')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def test_file(upload_location_dir):
|
|
||||||
"""Create test upload/download file."""
|
|
||||||
setattr(test_file, 'name', 'sample.txt')
|
|
||||||
setattr(test_file, 'location', upload_location_dir.join(test_file.name))
|
|
||||||
return test_file
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def download_file(upload_file):
|
|
||||||
"""Uploads and downloads a file"""
|
|
||||||
download = Download(upload_file.selenium, upload_file.file_url).open()
|
|
||||||
download.download_btn.click()
|
|
||||||
return download
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def upload_file(selenium, base_url, download_location_dir, test_file):
|
|
||||||
"""Upload file fixture."""
|
|
||||||
home = Home(selenium, base_url).open()
|
|
||||||
test_file.location.write('This is a test! This is a test!')
|
|
||||||
return home.upload_area("{0}".format(test_file.location.realpath()))
|
|
51
test/integration/download-tests.js
Normal file
51
test/integration/download-tests.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/* global browser document */
|
||||||
|
const assert = require('assert');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const DownloadPage = require('./pages/desktop/download_page');
|
||||||
|
const HomePage = require('./pages/desktop/home_page');
|
||||||
|
const SharePage = require('./pages/desktop/share_page');
|
||||||
|
|
||||||
|
describe('Firefox Send', function() {
|
||||||
|
const downloadDir =
|
||||||
|
browser.desiredCapabilities['moz:firefoxOptions']['prefs'][
|
||||||
|
'browser.download.dir'
|
||||||
|
];
|
||||||
|
const testFilesPath = path.join(__dirname, 'fixtures');
|
||||||
|
const testFiles = fs.readdirSync(testFilesPath);
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url('/');
|
||||||
|
browser.execute(() => {
|
||||||
|
document.getElementById('file-upload').style.display = 'block';
|
||||||
|
});
|
||||||
|
browser.waitForExist('#file-upload');
|
||||||
|
});
|
||||||
|
|
||||||
|
testFiles.forEach(file => {
|
||||||
|
it(`should upload and download files, file: ${file}`, function() {
|
||||||
|
browser.execute(() => {
|
||||||
|
document.getElementById('file-upload').style.display = 'block';
|
||||||
|
});
|
||||||
|
browser.waitForExist('#file-upload');
|
||||||
|
const homePage = new HomePage();
|
||||||
|
browser.chooseFile('#file-upload', `${testFilesPath}/${file}`);
|
||||||
|
browser.click(homePage.readyToSend);
|
||||||
|
const sharePage = new SharePage();
|
||||||
|
browser.waitForExist(sharePage.fileUrl);
|
||||||
|
browser.url(browser.getValue(sharePage.fileUrl));
|
||||||
|
const downloadPage = new DownloadPage();
|
||||||
|
downloadPage.waitForPageToLoad();
|
||||||
|
downloadPage.downloadBtn();
|
||||||
|
// Wait for download to complete
|
||||||
|
browser.waitUntil(() => {
|
||||||
|
browser.waitForExist(downloadPage.downloadComplete);
|
||||||
|
return (
|
||||||
|
browser.getText(downloadPage.downloadComplete) === 'DOWNLOAD COMPLETE'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
assert.ok(fs.existsSync(path.join(downloadDir, file)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
1
test/integration/fixtures/txt-larger-testfile.txt
Normal file
1
test/integration/fixtures/txt-larger-testfile.txt
Normal file
File diff suppressed because one or more lines are too long
1
test/integration/fixtures/txt-small-testfile.txt
Normal file
1
test/integration/fixtures/txt-small-testfile.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
THIS IS A TEST!
|
54
test/integration/homepage-tests.js
Normal file
54
test/integration/homepage-tests.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/* global browser */
|
||||||
|
const assert = require('assert');
|
||||||
|
const HomePage = require('./pages/desktop/home_page');
|
||||||
|
|
||||||
|
describe('Firefox Send homepage', function() {
|
||||||
|
const baseUrl = browser.options['baseUrl'];
|
||||||
|
const legalLinks = [
|
||||||
|
'legal',
|
||||||
|
'about',
|
||||||
|
'legal',
|
||||||
|
'cookies',
|
||||||
|
'report-infringement'
|
||||||
|
];
|
||||||
|
const socialLinks = ['github', 'twitter', 'mozilla'];
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url('/');
|
||||||
|
browser.pause(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the right title', function() {
|
||||||
|
assert.equal(browser.getTitle(), 'Firefox Send');
|
||||||
|
});
|
||||||
|
|
||||||
|
legalLinks.forEach((link, i) => {
|
||||||
|
it(`should navigate to the correct legal pages, page: ${link}`, function() {
|
||||||
|
const homePage = new HomePage();
|
||||||
|
// Click links on bottom of page
|
||||||
|
const els = browser.elements(homePage.legalLinks);
|
||||||
|
browser.elementIdClick(els.value[i].ELEMENT);
|
||||||
|
// Wait for page to load
|
||||||
|
browser.waitUntil(() => {
|
||||||
|
const url = browser.getUrl();
|
||||||
|
return url !== baseUrl;
|
||||||
|
});
|
||||||
|
assert.ok(browser.getUrl().includes(link));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socialLinks.forEach((link, i) => {
|
||||||
|
it(`should navigate to the correct social pages, page: ${link}`, function() {
|
||||||
|
const homePage = new HomePage();
|
||||||
|
// Click links on bottom of page
|
||||||
|
const els = browser.elements(homePage.socialLinks);
|
||||||
|
browser.elementIdClick(els.value[i].ELEMENT);
|
||||||
|
// Wait for page to load
|
||||||
|
browser.waitUntil(() => {
|
||||||
|
const url = browser.getUrl();
|
||||||
|
return url !== baseUrl;
|
||||||
|
});
|
||||||
|
assert.ok(browser.getUrl().includes(link));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,41 +0,0 @@
|
|||||||
from pypom import Page, Region
|
|
||||||
from selenium.webdriver.common.by import By
|
|
||||||
|
|
||||||
|
|
||||||
class Base(Page):
|
|
||||||
"""Base object model."""
|
|
||||||
|
|
||||||
_url = '{base_url}'
|
|
||||||
_send_logo_locator = (By.CLASS_NAME, 'logo')
|
|
||||||
|
|
||||||
def __init__(self, selenium, base_url, locale='en-US', **kwargs):
|
|
||||||
super(Base, self).__init__(
|
|
||||||
selenium, base_url, locale=locale, timeout=20, **kwargs)
|
|
||||||
|
|
||||||
def wait_for_page_to_load(self):
|
|
||||||
self.wait.until(
|
|
||||||
lambda _: self.find_element(
|
|
||||||
*self._send_logo_locator).is_displayed())
|
|
||||||
return self
|
|
||||||
|
|
||||||
@property
|
|
||||||
def footer(self):
|
|
||||||
return self.Footer(self)
|
|
||||||
|
|
||||||
class Footer(Region):
|
|
||||||
_root_element = (By.CLASS_NAME, 'footer')
|
|
||||||
_legal_links = (By.CLASS_NAME, 'legalSection__link')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def links(self):
|
|
||||||
return [self.Links(self, el) for el in self.find_elements(
|
|
||||||
*self._legal_links)]
|
|
||||||
|
|
||||||
class Links(Region):
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self.root.text.split()[0]
|
|
||||||
|
|
||||||
def click(self):
|
|
||||||
self.root.click()
|
|
@ -1,17 +0,0 @@
|
|||||||
from selenium.webdriver.common.by import By
|
|
||||||
|
|
||||||
from pages.desktop.base import Base
|
|
||||||
|
|
||||||
|
|
||||||
class Download(Base):
|
|
||||||
"""Download page object model."""
|
|
||||||
|
|
||||||
_download_button_locator = (By.CLASS_NAME, 'btn--download')
|
|
||||||
|
|
||||||
def wait_for_page_to_load(self):
|
|
||||||
self.wait.until(lambda _: self.download_btn.is_displayed())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def download_btn(self):
|
|
||||||
"""Download button."""
|
|
||||||
return self.find_element(*self._download_button_locator)
|
|
34
test/integration/pages/desktop/download_page.js
Normal file
34
test/integration/pages/desktop/download_page.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* global browser */
|
||||||
|
const Page = require('./page');
|
||||||
|
|
||||||
|
class DownloadPage extends Page {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.downloadBtnLocator = '.btn--download';
|
||||||
|
this.downloadCompletedLocator = '.btn--complete';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function waitForPageToLoad
|
||||||
|
* @returns {Object} An object representing the page.
|
||||||
|
* @throws ElementNotFound
|
||||||
|
*/
|
||||||
|
waitForPageToLoad() {
|
||||||
|
browser.waitUntil(() => {
|
||||||
|
browser.waitForExist(this.downloadBtnLocator);
|
||||||
|
const el = browser.element(this.downloadBtnLocator);
|
||||||
|
return browser.elementIdDisplayed(el.value.ELEMENT);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadBtn() {
|
||||||
|
this.waitForPageToLoad();
|
||||||
|
return browser.click(this.downloadBtnLocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
get downloadComplete() {
|
||||||
|
return this.downloadCompletedLocator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = DownloadPage;
|
@ -1,26 +0,0 @@
|
|||||||
from selenium.webdriver.common.by import By
|
|
||||||
|
|
||||||
from pages.desktop.base import Base
|
|
||||||
|
|
||||||
|
|
||||||
class Home(Base):
|
|
||||||
"""Firefox Send Home page object model."""
|
|
||||||
|
|
||||||
_upload_area_locator = (By.ID, 'file-upload')
|
|
||||||
_upload_button_locator = (By.CLASS_NAME, 'btn--file')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def upload_btn(self):
|
|
||||||
"""Upload button."""
|
|
||||||
return self.find_element(*self._upload_button_locator)
|
|
||||||
|
|
||||||
def upload_area(self, path, cancel=False):
|
|
||||||
"""Area that allows for drag and drop uploading.
|
|
||||||
|
|
||||||
Returns Progress Object.
|
|
||||||
"""
|
|
||||||
self.find_element(*self._upload_area_locator).send_keys(path)
|
|
||||||
from pages.desktop.progress import Progress
|
|
||||||
return Progress(
|
|
||||||
self.selenium, self.base_url).wait_for_page_to_load(
|
|
||||||
cancel_after_load=cancel)
|
|
23
test/integration/pages/desktop/home_page.js
Normal file
23
test/integration/pages/desktop/home_page.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
const Page = require('./page');
|
||||||
|
|
||||||
|
class HomePage extends Page {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.legalSectionLinks = '.legalSection .legalSection__link';
|
||||||
|
this.readyToSendLocator = 'div#page-one button.btn';
|
||||||
|
this.socialLinksLocator = '.socialSection__link';
|
||||||
|
}
|
||||||
|
|
||||||
|
get legalLinks() {
|
||||||
|
return this.legalSectionLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
get readyToSend() {
|
||||||
|
return this.readyToSendLocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
get socialLinks() {
|
||||||
|
return this.socialLinksLocator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = HomePage;
|
17
test/integration/pages/desktop/page.js
Normal file
17
test/integration/pages/desktop/page.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* global browser */
|
||||||
|
class Page {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
open(path) {
|
||||||
|
browser.url(path);
|
||||||
|
this.waitForPageToLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function waitForPageToLoad
|
||||||
|
* @returns {Object} An object representing the page.
|
||||||
|
* @throws ElementNotFound
|
||||||
|
*/
|
||||||
|
waitForPageToLoad() {}
|
||||||
|
}
|
||||||
|
module.exports = Page;
|
@ -1,25 +0,0 @@
|
|||||||
from selenium.webdriver.common.by import By
|
|
||||||
|
|
||||||
from pages.desktop.base import Base
|
|
||||||
|
|
||||||
|
|
||||||
class Progress(Base):
|
|
||||||
"""Progress page object model."""
|
|
||||||
|
|
||||||
_cancel_button = (By.ID, 'cancel-upload')
|
|
||||||
_progress_icon_locator = (By.CLASS_NAME, 'progress__bar')
|
|
||||||
|
|
||||||
def wait_for_page_to_load(self, cancel_after_load=False):
|
|
||||||
self.wait.until(
|
|
||||||
lambda _: self.find_element(
|
|
||||||
*self._progress_icon_locator).is_displayed())
|
|
||||||
if cancel_after_load:
|
|
||||||
self.cancel_btn.click()
|
|
||||||
return
|
|
||||||
from pages.desktop.share import Share
|
|
||||||
return Share(self.selenium, self.base_url).wait_for_page_to_load()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cancel_btn(self):
|
|
||||||
"""Cancel upload button."""
|
|
||||||
return self.find_element(*self._cancel_button)
|
|
31
test/integration/pages/desktop/progress_page.js
Normal file
31
test/integration/pages/desktop/progress_page.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/* global browser */
|
||||||
|
const Page = require('./page');
|
||||||
|
const SharePage = require('./share_page');
|
||||||
|
|
||||||
|
class ProgressPage extends Page {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.cancelBtnLocator = '.uploadCancel';
|
||||||
|
this.progressIconLocator = '.btn--stripes';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function waitForPageToLoad
|
||||||
|
* @returns {Object} An object representing the Share page.
|
||||||
|
* @throws ElementNotFound
|
||||||
|
*/
|
||||||
|
waitForPageToLoad() {
|
||||||
|
browser.waitUntil(() => {
|
||||||
|
browser.waitForExist(this.progressIconLocator);
|
||||||
|
const el = browser.element(this.progressIconLocator);
|
||||||
|
return browser.elementIdDisplayed(el.value.ELEMENT);
|
||||||
|
});
|
||||||
|
const sharePage = new SharePage();
|
||||||
|
return sharePage.waitForPageToLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
get cancelBtn() {
|
||||||
|
return this.cancelBtnLocator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = ProgressPage;
|
@ -1,22 +0,0 @@
|
|||||||
from selenium.webdriver.common.by import By
|
|
||||||
|
|
||||||
from pages.desktop.base import Base
|
|
||||||
|
|
||||||
|
|
||||||
class Share(Base):
|
|
||||||
"""SHare page object model."""
|
|
||||||
|
|
||||||
_share_page_locator = (By.CLASS_NAME, 'sharePage')
|
|
||||||
_share_url_locator = (By.ID, 'fileUrl')
|
|
||||||
|
|
||||||
def wait_for_page_to_load(self):
|
|
||||||
self.wait.until(
|
|
||||||
lambda _: self.find_element(
|
|
||||||
*self._share_page_locator).is_displayed())
|
|
||||||
return self
|
|
||||||
|
|
||||||
@property
|
|
||||||
def file_url(self):
|
|
||||||
"""File uploaded URL."""
|
|
||||||
return self.find_element(
|
|
||||||
*self._share_url_locator).get_property('value')
|
|
24
test/integration/pages/desktop/share_page.js
Normal file
24
test/integration/pages/desktop/share_page.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* global browser */
|
||||||
|
const Page = require('./page');
|
||||||
|
|
||||||
|
class SharePage extends Page {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.sharePageLocator = '#shareWrapper';
|
||||||
|
this.shareUrlLocator = '#fileUrl';
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForPageToLoad() {
|
||||||
|
browser.waitUntil(() => {
|
||||||
|
browser.waitForExist(this.sharePageLocator);
|
||||||
|
const el = browser.element(this.sharePageLocator);
|
||||||
|
return browser.elementIdDisplayed(el.value.ELEMENT);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get fileUrl() {
|
||||||
|
return this.shareUrlLocator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = SharePage;
|
22
test/integration/progress-tests.js
Normal file
22
test/integration/progress-tests.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/* global browser document */
|
||||||
|
const assert = require('assert');
|
||||||
|
const ProgressPage = require('./pages/desktop/progress_page');
|
||||||
|
const HomePage = require('./pages/desktop/home_page');
|
||||||
|
|
||||||
|
describe('Firefox Send progress page', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show an icon while an upload is in progress', function() {
|
||||||
|
browser.execute(() => {
|
||||||
|
document.getElementById('file-upload').style.display = 'block';
|
||||||
|
});
|
||||||
|
browser.waitForExist('#file-upload');
|
||||||
|
const homePage = new HomePage();
|
||||||
|
browser.chooseFile('#file-upload', __filename);
|
||||||
|
browser.click(homePage.readyToSend);
|
||||||
|
const progressPage = new ProgressPage();
|
||||||
|
assert.ok(progressPage.waitForPageToLoad());
|
||||||
|
});
|
||||||
|
});
|
@ -1,8 +0,0 @@
|
|||||||
selenium==3.13.0
|
|
||||||
flake8==3.5.0
|
|
||||||
flake8-isort==2.5
|
|
||||||
PyPOM==2.0.0
|
|
||||||
pytest==3.6.3
|
|
||||||
pytest-html==1.19.0
|
|
||||||
pytest-selenium==1.13.0
|
|
||||||
pytest-xdist==1.22.2
|
|
464
test/integration/send-test.html
Normal file
464
test/integration/send-test.html
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>Test Report</title>
|
||||||
|
<style>body {
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
min-width: 1200px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 16px;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* SUMMARY INFORMATION
|
||||||
|
******************************/
|
||||||
|
|
||||||
|
#environment td {
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #E6E6E6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#environment tr:nth-child(odd) {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* TEST RESULT COLORS
|
||||||
|
******************************/
|
||||||
|
span.passed, .passed .col-result {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
span.skipped, span.xfailed, span.rerun, .skipped .col-result, .xfailed .col-result, .rerun .col-result {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
span.error, span.failed, span.xpassed, .error .col-result, .failed .col-result, .xpassed .col-result {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* RESULTS TABLE
|
||||||
|
*
|
||||||
|
* 1. Table Layout
|
||||||
|
* 2. Extra
|
||||||
|
* 3. Sorting items
|
||||||
|
*
|
||||||
|
******************************/
|
||||||
|
|
||||||
|
/*------------------
|
||||||
|
* 1. Table Layout
|
||||||
|
*------------------*/
|
||||||
|
|
||||||
|
#results-table {
|
||||||
|
border: 1px solid #e6e6e6;
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
#results-table th, #results-table td {
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #E6E6E6;
|
||||||
|
text-align: left
|
||||||
|
}
|
||||||
|
#results-table th {
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------
|
||||||
|
* 2. Extra
|
||||||
|
*------------------*/
|
||||||
|
|
||||||
|
.log:only-child {
|
||||||
|
height: inherit
|
||||||
|
}
|
||||||
|
.log {
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
border: 1px solid #e6e6e6;
|
||||||
|
color: black;
|
||||||
|
display: block;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
height: 230px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 5px;
|
||||||
|
white-space: pre-wrap
|
||||||
|
}
|
||||||
|
div.image {
|
||||||
|
border: 1px solid #e6e6e6;
|
||||||
|
float: right;
|
||||||
|
height: 240px;
|
||||||
|
margin-left: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 320px
|
||||||
|
}
|
||||||
|
div.image img {
|
||||||
|
width: 320px
|
||||||
|
}
|
||||||
|
.collapsed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.expander::after {
|
||||||
|
content: " (show details)";
|
||||||
|
color: #BBB;
|
||||||
|
font-style: italic;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.collapser::after {
|
||||||
|
content: " (hide details)";
|
||||||
|
color: #BBB;
|
||||||
|
font-style: italic;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------
|
||||||
|
* 3. Sorting items
|
||||||
|
*------------------*/
|
||||||
|
.sortable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-icon {
|
||||||
|
font-size: 0px;
|
||||||
|
float: left;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
/*triangle*/
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 8px solid transparent;
|
||||||
|
border-right: 8px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inactive .sort-icon {
|
||||||
|
/*finish triangle*/
|
||||||
|
border-top: 8px solid #E6E6E6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asc.active .sort-icon {
|
||||||
|
/*finish triangle*/
|
||||||
|
border-bottom: 8px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc.active .sort-icon {
|
||||||
|
/*finish triangle*/
|
||||||
|
border-top: 8px solid #999;
|
||||||
|
}
|
||||||
|
</style></head>
|
||||||
|
<body onLoad="init()">
|
||||||
|
<script>/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
|
||||||
|
function toArray(iter) {
|
||||||
|
if (iter === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Array.prototype.slice.call(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function find(selector, elem) {
|
||||||
|
if (!elem) {
|
||||||
|
elem = document;
|
||||||
|
}
|
||||||
|
return elem.querySelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
function find_all(selector, elem) {
|
||||||
|
if (!elem) {
|
||||||
|
elem = document;
|
||||||
|
}
|
||||||
|
return toArray(elem.querySelectorAll(selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort_column(elem) {
|
||||||
|
toggle_sort_states(elem);
|
||||||
|
var colIndex = toArray(elem.parentNode.childNodes).indexOf(elem);
|
||||||
|
var key;
|
||||||
|
if (elem.classList.contains('numeric')) {
|
||||||
|
key = key_num;
|
||||||
|
} else if (elem.classList.contains('result')) {
|
||||||
|
key = key_result;
|
||||||
|
} else {
|
||||||
|
key = key_alpha;
|
||||||
|
}
|
||||||
|
sort_table(elem, key(colIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_all_extras() {
|
||||||
|
find_all('.col-result').forEach(show_extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_all_extras() {
|
||||||
|
find_all('.col-result').forEach(hide_extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_extras(colresult_elem) {
|
||||||
|
var extras = colresult_elem.parentNode.nextElementSibling;
|
||||||
|
var expandcollapse = colresult_elem.firstElementChild;
|
||||||
|
extras.classList.remove("collapsed");
|
||||||
|
expandcollapse.classList.remove("expander");
|
||||||
|
expandcollapse.classList.add("collapser");
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_extras(colresult_elem) {
|
||||||
|
var extras = colresult_elem.parentNode.nextElementSibling;
|
||||||
|
var expandcollapse = colresult_elem.firstElementChild;
|
||||||
|
extras.classList.add("collapsed");
|
||||||
|
expandcollapse.classList.remove("collapser");
|
||||||
|
expandcollapse.classList.add("expander");
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_filters() {
|
||||||
|
var filter_items = document.getElementsByClassName('filter');
|
||||||
|
for (var i = 0; i < filter_items.length; i++)
|
||||||
|
filter_items[i].hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_collapse() {
|
||||||
|
// Add links for show/hide all
|
||||||
|
var resulttable = find('table#results-table');
|
||||||
|
var showhideall = document.createElement("p");
|
||||||
|
showhideall.innerHTML = '<a href="javascript:show_all_extras()">Show all details</a> / ' +
|
||||||
|
'<a href="javascript:hide_all_extras()">Hide all details</a>';
|
||||||
|
resulttable.parentElement.insertBefore(showhideall, resulttable);
|
||||||
|
|
||||||
|
// Add show/hide link to each result
|
||||||
|
find_all('.col-result').forEach(function(elem) {
|
||||||
|
var collapsed = get_query_parameter('collapsed') || 'Passed';
|
||||||
|
var extras = elem.parentNode.nextElementSibling;
|
||||||
|
var expandcollapse = document.createElement("span");
|
||||||
|
if (collapsed.includes(elem.innerHTML)) {
|
||||||
|
extras.classList.add("collapsed");
|
||||||
|
expandcollapse.classList.add("expander");
|
||||||
|
} else {
|
||||||
|
expandcollapse.classList.add("collapser");
|
||||||
|
}
|
||||||
|
elem.appendChild(expandcollapse);
|
||||||
|
|
||||||
|
elem.addEventListener("click", function(event) {
|
||||||
|
if (event.currentTarget.parentNode.nextElementSibling.classList.contains("collapsed")) {
|
||||||
|
show_extras(event.currentTarget);
|
||||||
|
} else {
|
||||||
|
hide_extras(event.currentTarget);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_query_parameter(name) {
|
||||||
|
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
|
||||||
|
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
reset_sort_headers();
|
||||||
|
|
||||||
|
add_collapse();
|
||||||
|
|
||||||
|
show_filters();
|
||||||
|
|
||||||
|
toggle_sort_states(find('.initial-sort'));
|
||||||
|
|
||||||
|
find_all('.sortable').forEach(function(elem) {
|
||||||
|
elem.addEventListener("click",
|
||||||
|
function(event) {
|
||||||
|
sort_column(elem);
|
||||||
|
}, false)
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function sort_table(clicked, key_func) {
|
||||||
|
var rows = find_all('.results-table-row');
|
||||||
|
var reversed = !clicked.classList.contains('asc');
|
||||||
|
var sorted_rows = sort(rows, key_func, reversed);
|
||||||
|
/* Whole table is removed here because browsers acts much slower
|
||||||
|
* when appending existing elements.
|
||||||
|
*/
|
||||||
|
var thead = document.getElementById("results-table-head");
|
||||||
|
document.getElementById('results-table').remove();
|
||||||
|
var parent = document.createElement("table");
|
||||||
|
parent.id = "results-table";
|
||||||
|
parent.appendChild(thead);
|
||||||
|
sorted_rows.forEach(function(elem) {
|
||||||
|
parent.appendChild(elem);
|
||||||
|
});
|
||||||
|
document.getElementsByTagName("BODY")[0].appendChild(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort(items, key_func, reversed) {
|
||||||
|
var sort_array = items.map(function(item, i) {
|
||||||
|
return [key_func(item), i];
|
||||||
|
});
|
||||||
|
var multiplier = reversed ? -1 : 1;
|
||||||
|
|
||||||
|
sort_array.sort(function(a, b) {
|
||||||
|
var key_a = a[0];
|
||||||
|
var key_b = b[0];
|
||||||
|
return multiplier * (key_a >= key_b ? 1 : -1);
|
||||||
|
});
|
||||||
|
|
||||||
|
return sort_array.map(function(item) {
|
||||||
|
var index = item[1];
|
||||||
|
return items[index];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function key_alpha(col_index) {
|
||||||
|
return function(elem) {
|
||||||
|
return elem.childNodes[1].childNodes[col_index].firstChild.data.toLowerCase();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function key_num(col_index) {
|
||||||
|
return function(elem) {
|
||||||
|
return parseFloat(elem.childNodes[1].childNodes[col_index].firstChild.data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function key_result(col_index) {
|
||||||
|
return function(elem) {
|
||||||
|
var strings = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed',
|
||||||
|
'Skipped', 'Passed'];
|
||||||
|
return strings.indexOf(elem.childNodes[1].childNodes[col_index].firstChild.data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset_sort_headers() {
|
||||||
|
find_all('.sort-icon').forEach(function(elem) {
|
||||||
|
elem.parentNode.removeChild(elem);
|
||||||
|
});
|
||||||
|
find_all('.sortable').forEach(function(elem) {
|
||||||
|
var icon = document.createElement("div");
|
||||||
|
icon.className = "sort-icon";
|
||||||
|
icon.textContent = "vvv";
|
||||||
|
elem.insertBefore(icon, elem.firstChild);
|
||||||
|
elem.classList.remove("desc", "active");
|
||||||
|
elem.classList.add("asc", "inactive");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle_sort_states(elem) {
|
||||||
|
//if active, toggle between asc and desc
|
||||||
|
if (elem.classList.contains('active')) {
|
||||||
|
elem.classList.toggle('asc');
|
||||||
|
elem.classList.toggle('desc');
|
||||||
|
}
|
||||||
|
|
||||||
|
//if inactive, reset all other functions and add ascending active
|
||||||
|
if (elem.classList.contains('inactive')) {
|
||||||
|
reset_sort_headers();
|
||||||
|
elem.classList.remove('inactive');
|
||||||
|
elem.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_all_rows_hidden(value) {
|
||||||
|
return value.hidden == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter_table(elem) {
|
||||||
|
var outcome_att = "data-test-result";
|
||||||
|
var outcome = elem.getAttribute(outcome_att);
|
||||||
|
class_outcome = outcome + " results-table-row";
|
||||||
|
var outcome_rows = document.getElementsByClassName(class_outcome);
|
||||||
|
|
||||||
|
for(var i = 0; i < outcome_rows.length; i++){
|
||||||
|
outcome_rows[i].hidden = !elem.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows = find_all('.results-table-row').filter(is_all_rows_hidden);
|
||||||
|
var all_rows_hidden = rows.length == 0 ? true : false;
|
||||||
|
var not_found_message = document.getElementById("not-found-message");
|
||||||
|
not_found_message.hidden = !all_rows_hidden;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<h1>send-test.html</h1>
|
||||||
|
<p>Report generated on 14-Jun-2018 at 14:20:27 by<a href="https://pypi.python.org/pypi/pytest-html"> pytest-html</a> v1.19.0</p>
|
||||||
|
<h2>Environment</h2>
|
||||||
|
<table id="environment">
|
||||||
|
<tr>
|
||||||
|
<td>Base URL</td>
|
||||||
|
<td><a href="http://localhost:1443" target="_blank">http://localhost:1443</a></td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>Driver</td>
|
||||||
|
<td>Firefox</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>JAVA_HOME</td>
|
||||||
|
<td>/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>Packages</td>
|
||||||
|
<td>{'pytest': '3.6.1', 'py': '1.5.3', 'pluggy': '0.6.0'}</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>Platform</td>
|
||||||
|
<td>Darwin-17.5.0-x86_64-i386-64bit</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>Plugins</td>
|
||||||
|
<td>{'xdist': '1.22.2', 'variables': '1.7.1', 'selenium': '1.13.0', 'metadata': '1.7.0', 'html': '1.19.0', 'forked': '0.2', 'base-url': '1.4.1'}</td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>Python</td>
|
||||||
|
<td>3.6.5</td></tr></table>
|
||||||
|
<h2>Summary</h2>
|
||||||
|
<p>3 tests ran in 20.54 seconds. </p>
|
||||||
|
<p class="filter" hidden="true">(Un)check the boxes to filter the results.</p><input checked="true" class="filter" data-test-result="passed" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="passed">3 passed</span>, <input checked="true" class="filter" data-test-result="skipped" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="skipped">0 skipped</span>, <input checked="true" class="filter" data-test-result="failed" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="failed">0 failed</span>, <input checked="true" class="filter" data-test-result="error" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="error">0 errors</span>, <input checked="true" class="filter" data-test-result="xfailed" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="xfailed">0 expected failures</span>, <input checked="true" class="filter" data-test-result="xpassed" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="xpassed">0 unexpected passes</span>
|
||||||
|
<h2>Results</h2>
|
||||||
|
<table id="results-table">
|
||||||
|
<thead id="results-table-head">
|
||||||
|
<tr>
|
||||||
|
<th class="sortable result initial-sort" col="result">Result</th>
|
||||||
|
<th class="sortable" col="name">Test</th>
|
||||||
|
<th class="sortable numeric" col="duration">Duration</th>
|
||||||
|
<th>Links</th></tr>
|
||||||
|
<tr hidden="true" id="not-found-message">
|
||||||
|
<th colspan="4">No results found. Try to check the filters</th></tr></thead>
|
||||||
|
<tbody class="passed results-table-row">
|
||||||
|
<tr>
|
||||||
|
<td class="col-result">Passed</td>
|
||||||
|
<td class="col-name">test_download.py::test_download</td>
|
||||||
|
<td class="col-duration">0.00</td>
|
||||||
|
<td class="col-links"></td></tr>
|
||||||
|
<tr>
|
||||||
|
<td class="extra" colspan="4">
|
||||||
|
<div class="empty log">No log output captured.</div></td></tr></tbody>
|
||||||
|
<tbody class="passed results-table-row">
|
||||||
|
<tr>
|
||||||
|
<td class="col-result">Passed</td>
|
||||||
|
<td class="col-name">test_progress.py::test_progress</td>
|
||||||
|
<td class="col-duration">0.00</td>
|
||||||
|
<td class="col-links"></td></tr>
|
||||||
|
<tr>
|
||||||
|
<td class="extra" colspan="4">
|
||||||
|
<div class="empty log">No log output captured.</div></td></tr></tbody>
|
||||||
|
<tbody class="passed results-table-row">
|
||||||
|
<tr>
|
||||||
|
<td class="col-result">Passed</td>
|
||||||
|
<td class="col-name">test_upload.py::test_upload</td>
|
||||||
|
<td class="col-duration">0.01</td>
|
||||||
|
<td class="col-links"></td></tr>
|
||||||
|
<tr>
|
||||||
|
<td class="extra" colspan="4">
|
||||||
|
<div class="empty log">No log output captured.</div></td></tr></tbody></table></body></html>
|
@ -1,6 +0,0 @@
|
|||||||
"""Test files regarding downloads."""
|
|
||||||
|
|
||||||
|
|
||||||
def test_download(download_file, download_location_dir, test_file):
|
|
||||||
"""Test downloaded file matches uploaded file."""
|
|
||||||
assert download_location_dir.ensure(test_file.name)
|
|
@ -1,14 +0,0 @@
|
|||||||
import pytest
|
|
||||||
|
|
||||||
from pages.desktop.base import Base
|
|
||||||
|
|
||||||
footer_links = ['mozilla', 'mozilla', 'about', 'legal', 'legal', 'cookies',
|
|
||||||
'report-infringement']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('i, name', enumerate(footer_links))
|
|
||||||
def test_legal_links(selenium, base_url, i, name):
|
|
||||||
"""Test links in footer load correct pages."""
|
|
||||||
page = Base(selenium, base_url).open()
|
|
||||||
page.footer.links[i].click()
|
|
||||||
assert name in selenium.current_url
|
|
@ -1,6 +0,0 @@
|
|||||||
"""Test files regarding the upload progress pages."""
|
|
||||||
|
|
||||||
|
|
||||||
def test_progress(upload_file):
|
|
||||||
"""Test progress icon shows while uploading."""
|
|
||||||
assert upload_file
|
|
@ -1,6 +0,0 @@
|
|||||||
"""Test files regarding uploading."""
|
|
||||||
|
|
||||||
|
|
||||||
def test_upload(upload_file):
|
|
||||||
"""Test file upload and creates URL."""
|
|
||||||
assert upload_file.file_url is not None
|
|
@ -1,19 +0,0 @@
|
|||||||
[tox]
|
|
||||||
envlist = integration-tests, flake8
|
|
||||||
skipsdist = True
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
skip_install = True
|
|
||||||
deps = -rrequirements.txt
|
|
||||||
commands =
|
|
||||||
pytest -v --verify-base-url --base-url {env:BASE_URL:http://web:1443} --driver Remote --capability browserName firefox --host selenium --html=/coverage/send-test.html --self-contained-html {posargs}
|
|
||||||
|
|
||||||
[testenv:flake8]
|
|
||||||
commands =
|
|
||||||
flake8 {posargs:.}
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
exclude = .eggs,.tox,docs,node_modules
|
|
||||||
|
|
||||||
[pytest]
|
|
||||||
sensitive_url = mozilla\.(com|org)
|
|
34
test/testServer.js
Normal file
34
test/testServer.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
let server = null;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
onPrepare: function() {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const middleware = require('webpack-dev-middleware');
|
||||||
|
const express = require('express');
|
||||||
|
const expressWs = require('express-ws');
|
||||||
|
const assets = require('../common/assets');
|
||||||
|
const locales = require('../common/locales');
|
||||||
|
const routes = require('../server/routes');
|
||||||
|
const tests = require('./frontend/routes');
|
||||||
|
const app = express();
|
||||||
|
const config = require('../webpack.config');
|
||||||
|
const wpm = middleware(webpack(config(null, { mode: 'development' })), {
|
||||||
|
logLevel: 'silent'
|
||||||
|
});
|
||||||
|
app.use(wpm);
|
||||||
|
assets.setMiddleware(wpm);
|
||||||
|
locales.setMiddleware(wpm);
|
||||||
|
expressWs(app, null, { perMessageDeflate: false });
|
||||||
|
app.ws('/api/ws', require('../server/routes/ws'));
|
||||||
|
routes(app);
|
||||||
|
tests(app);
|
||||||
|
wpm.waitUntilValid(() => {
|
||||||
|
server = app.listen(8000, resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onComplete: function() {
|
||||||
|
server.close();
|
||||||
|
}
|
||||||
|
};
|
18
test/wdio.circleci.conf.js
Normal file
18
test/wdio.circleci.conf.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// eslint-disable-next-line node/no-extraneous-require
|
||||||
|
const ip = require('ip');
|
||||||
|
const path = require('path');
|
||||||
|
const common = require('./wdio.common.conf');
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
Config for running selenium from a circleci docker container against localhost
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
exports.config = Object.assign({}, common.config, {
|
||||||
|
baseUrl: `http://${ip.address()}:8000`,
|
||||||
|
exclude: [path.join(__dirname, './integration/download-tests.js')],
|
||||||
|
maxInstances: 1,
|
||||||
|
bail: 1,
|
||||||
|
services: [require('./testServer')]
|
||||||
|
});
|
48
test/wdio.common.conf.js
Normal file
48
test/wdio.common.conf.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const mkdirp = require('mkdirp');
|
||||||
|
const rimraf = require('rimraf');
|
||||||
|
const dir = path.join(__dirname, 'integration', 'downloads');
|
||||||
|
|
||||||
|
mkdirp.sync(dir);
|
||||||
|
rimraf.sync(`${dir}${path.sep}*`);
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
specs: [path.join(__dirname, './integration/**/*-tests.js')],
|
||||||
|
exclude: [],
|
||||||
|
maxInstances: 10,
|
||||||
|
capabilities: [
|
||||||
|
{
|
||||||
|
browserName: 'firefox',
|
||||||
|
'moz:firefoxOptions': {
|
||||||
|
log: { level: 'trace' },
|
||||||
|
prefs: {
|
||||||
|
'browser.download.panel.shown': false,
|
||||||
|
'browser.helperApps.neverAsk.openFile': 'text/plain',
|
||||||
|
'browser.helperApps.neverAsk.saveToDisk': 'text/plain',
|
||||||
|
'browser.download.folderList': 2,
|
||||||
|
'browser.download.dir': dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
pageLoadStrategy: 'normal',
|
||||||
|
watch: false,
|
||||||
|
async: true,
|
||||||
|
logLevel: 'error',
|
||||||
|
coloredLogs: true,
|
||||||
|
deprecationWarnings: true,
|
||||||
|
bail: 0,
|
||||||
|
screenshotOnReject: false,
|
||||||
|
baseUrl: 'http://localhost:8000',
|
||||||
|
waitforTimeout: 20000,
|
||||||
|
connectionRetryTimeout: 90000,
|
||||||
|
connectionRetryCount: 3,
|
||||||
|
services: ['firefox-profile'],
|
||||||
|
framework: 'mocha',
|
||||||
|
reporters: ['dot', 'spec'],
|
||||||
|
mochaOpts: {
|
||||||
|
ui: 'bdd',
|
||||||
|
timeout: 30000,
|
||||||
|
retries: 1
|
||||||
|
}
|
||||||
|
};
|
28
test/wdio.docker.conf.js
Normal file
28
test/wdio.docker.conf.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// eslint-disable-next-line node/no-extraneous-require
|
||||||
|
const ip = require('ip');
|
||||||
|
const common = require('./wdio.common.conf');
|
||||||
|
const dir =
|
||||||
|
common.config.capabilities[0]['moz:firefoxOptions'].prefs[
|
||||||
|
'browser.download.dir'
|
||||||
|
];
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
Config for running selenium in a new docker container against localhost
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
exports.config = Object.assign({}, common.config, {
|
||||||
|
baseUrl: `http://${ip.address()}:8000`,
|
||||||
|
maxInstances: 1,
|
||||||
|
services: ['docker', require('./testServer')],
|
||||||
|
dockerOptions: {
|
||||||
|
image: 'selenium/standalone-firefox',
|
||||||
|
healthCheck: 'http://localhost:4444',
|
||||||
|
options: {
|
||||||
|
p: ['4444:4444'],
|
||||||
|
mount: `type=bind,source=${dir},destination=${dir},consistency=delegated`,
|
||||||
|
shmSize: '2g'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
16
test/wdio.local.conf.js
Normal file
16
test/wdio.local.conf.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// eslint-disable-next-line node/no-extraneous-require
|
||||||
|
const ip = require('ip');
|
||||||
|
const common = require('./wdio.common.conf');
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
Config for running selenium against localhost
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
exports.config = Object.assign({}, common.config, {
|
||||||
|
baseUrl: `http://${ip.address()}:8000`,
|
||||||
|
maxInstances: 1,
|
||||||
|
bail: 1,
|
||||||
|
services: [require('./testServer')]
|
||||||
|
});
|
29
test/wdio.remote.config.js
Normal file
29
test/wdio.remote.config.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const common = require('./wdio.common.conf');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
Config for running saucelabs against a hosted server
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
exports.config = Object.assign({}, common.config, {
|
||||||
|
baseUrl: process.env.TEST_SERVER || 'https://send.dev.mozaws.net',
|
||||||
|
exclude: [
|
||||||
|
// the /test endpoint only exists on localhost
|
||||||
|
path.join(__dirname, './integration/unit-tests.js'),
|
||||||
|
// we don't have access to the fs in this context
|
||||||
|
path.join(__dirname, './integration/download-tests.js')
|
||||||
|
],
|
||||||
|
capabilities: [
|
||||||
|
{ browserName: 'firefox' },
|
||||||
|
{ browserName: 'chrome' },
|
||||||
|
{ browserName: 'MicrosoftEdge' },
|
||||||
|
{
|
||||||
|
browserName: 'safari'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
services: ['sauce'],
|
||||||
|
user: process.env.SAUCE_USERNAME,
|
||||||
|
key: process.env.SAUCE_ACCESS_KEY
|
||||||
|
});
|
30
test/wdio.saucelabs.config.js
Normal file
30
test/wdio.saucelabs.config.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const common = require('./wdio.common.conf');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
Config for running saucelabs against localhost
|
||||||
|
|
||||||
|
/*/
|
||||||
|
|
||||||
|
exports.config = Object.assign({}, common.config, {
|
||||||
|
maxInstances: 2,
|
||||||
|
exclude: [path.join(__dirname, './integration/download-tests.js')],
|
||||||
|
capabilities: [
|
||||||
|
{ browserName: 'firefox' },
|
||||||
|
{ browserName: 'chrome' },
|
||||||
|
{ browserName: 'MicrosoftEdge' },
|
||||||
|
{
|
||||||
|
browserName: 'safari'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
services: ['sauce', require('./testServer')],
|
||||||
|
sauceConnect: true,
|
||||||
|
sauceConnectOpts: {
|
||||||
|
// uncomment to debug
|
||||||
|
// logfile: __dirname + '/sc.log',
|
||||||
|
// verbose: true
|
||||||
|
},
|
||||||
|
user: process.env.SAUCE_USERNAME,
|
||||||
|
key: process.env.SAUCE_ACCESS_KEY
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user