QA bug fixes
This commit is contained in:
parent
07b7bc003a
commit
8e14d3f8f7
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
assets/*.js
|
|
@ -51,7 +51,7 @@ export default function initialize(state, emitter) {
|
||||||
emitter.on('DOMContentLoaded', () => {
|
emitter.on('DOMContentLoaded', () => {
|
||||||
const xp = experiments[state.query.x];
|
const xp = experiments[state.query.x];
|
||||||
if (xp) {
|
if (xp) {
|
||||||
xp.run(state.query.v, state, emitter);
|
xp.run(+state.query.v, state, emitter);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* global EXPIRE_SECONDS */
|
/* global EXPIRE_SECONDS */
|
||||||
import FileSender from './fileSender';
|
import FileSender from './fileSender';
|
||||||
import FileReceiver from './fileReceiver';
|
import FileReceiver from './fileReceiver';
|
||||||
import { copyToClipboard, delay, fadeOut } from './utils';
|
import { copyToClipboard, delay, fadeOut, percent } from './utils';
|
||||||
import * as metrics from './metrics';
|
import * as metrics from './metrics';
|
||||||
|
|
||||||
function saveFile(file) {
|
function saveFile(file) {
|
||||||
|
@ -54,6 +54,7 @@ function exists(id) {
|
||||||
|
|
||||||
export default function(state, emitter) {
|
export default function(state, emitter) {
|
||||||
let lastRender = 0;
|
let lastRender = 0;
|
||||||
|
let updateTitle = false;
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
emitter.emit('render');
|
emitter.emit('render');
|
||||||
|
@ -74,7 +75,21 @@ export default function(state, emitter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitter.on('DOMContentLoaded', checkFiles);
|
function updateProgress() {
|
||||||
|
if (updateTitle) {
|
||||||
|
emitter.emit('DOMTitleChange', percent(state.transfer.progressRatio));
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.on('DOMContentLoaded', () => {
|
||||||
|
document.addEventListener('blur', () => (updateTitle = true));
|
||||||
|
document.addEventListener('focus', () => {
|
||||||
|
updateTitle = false;
|
||||||
|
emitter.emit('DOMTitleChange', 'Firefox Send');
|
||||||
|
});
|
||||||
|
checkFiles();
|
||||||
|
});
|
||||||
|
|
||||||
emitter.on('navigate', checkFiles);
|
emitter.on('navigate', checkFiles);
|
||||||
|
|
||||||
|
@ -107,7 +122,7 @@ export default function(state, emitter) {
|
||||||
emitter.on('upload', async ({ file, type }) => {
|
emitter.on('upload', async ({ file, type }) => {
|
||||||
const size = file.size;
|
const size = file.size;
|
||||||
const sender = new FileSender(file);
|
const sender = new FileSender(file);
|
||||||
sender.on('progress', render);
|
sender.on('progress', updateProgress);
|
||||||
sender.on('encrypting', render);
|
sender.on('encrypting', render);
|
||||||
state.transfer = sender;
|
state.transfer = sender;
|
||||||
render();
|
render();
|
||||||
|
@ -153,7 +168,7 @@ export default function(state, emitter) {
|
||||||
const size = file.size;
|
const size = file.size;
|
||||||
const url = `/api/download/${file.id}`;
|
const url = `/api/download/${file.id}`;
|
||||||
const receiver = new FileReceiver(url, file.key);
|
const receiver = new FileReceiver(url, file.key);
|
||||||
receiver.on('progress', render);
|
receiver.on('progress', updateProgress);
|
||||||
receiver.on('decrypting', render);
|
receiver.on('decrypting', render);
|
||||||
state.transfer = receiver;
|
state.transfer = receiver;
|
||||||
const links = openLinksInNewTab();
|
const links = openLinksInNewTab();
|
||||||
|
|
|
@ -28,6 +28,13 @@ app.use((state, emitter) => {
|
||||||
uploadButtonStyle: 'browse btn'
|
uploadButtonStyle: 'browse btn'
|
||||||
};
|
};
|
||||||
emitter.on('DOMContentLoaded', async () => {
|
emitter.on('DOMContentLoaded', async () => {
|
||||||
|
if (
|
||||||
|
/firefox/i.test(navigator.userAgent) &&
|
||||||
|
parseInt(navigator.userAgent.match(/firefox\/*([^\n\r]*)\./i)[1], 10) <=
|
||||||
|
49
|
||||||
|
) {
|
||||||
|
return emitter.emit('replaceState', '/unsupported/outdated');
|
||||||
|
}
|
||||||
const ok = await canHasSend(assets.get('cryptofill.js'));
|
const ok = await canHasSend(assets.get('cryptofill.js'));
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
const reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';
|
const reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';
|
||||||
|
|
|
@ -4,7 +4,7 @@ const assets = require('../../common/assets');
|
||||||
function timeLeft(milliseconds) {
|
function timeLeft(milliseconds) {
|
||||||
const minutes = Math.floor(milliseconds / 1000 / 60);
|
const minutes = Math.floor(milliseconds / 1000 / 60);
|
||||||
const hours = Math.floor(minutes / 60);
|
const hours = Math.floor(minutes / 60);
|
||||||
const seconds = Math.floor(milliseconds / 1000 % 60);
|
const seconds = Math.floor((milliseconds / 1000) % 60);
|
||||||
if (hours >= 1) {
|
if (hours >= 1) {
|
||||||
return `${hours}h ${minutes % 60}m`;
|
return `${hours}h ${minutes % 60}m`;
|
||||||
} else if (hours === 0) {
|
} else if (hours === 0) {
|
||||||
|
|
|
@ -40,11 +40,16 @@ module.exports = function(state, emit) {
|
||||||
state.translate('downloadFileSize', { size })}</span>
|
state.translate('downloadFileSize', { size })}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">${state.translate('downloadMessage')}</div>
|
<div class="description">${state.translate('downloadMessage')}</div>
|
||||||
<img src="${assets.get(
|
<img
|
||||||
'illustration_download.svg'
|
src="${assets.get('illustration_download.svg')}"
|
||||||
)}" id="download-img" alt="${state.translate('downloadAltText')}"/>
|
id="download-img"
|
||||||
|
alt="${state.translate('downloadAltText')}"/>
|
||||||
<div>
|
<div>
|
||||||
<button id="download-btn" class="btn" onclick=${download}>${state.translate(
|
<button
|
||||||
|
id="download-btn"
|
||||||
|
class="btn"
|
||||||
|
title="${state.translate('downloadButtonLabel')}"
|
||||||
|
onclick=${download}>${state.translate(
|
||||||
'downloadButtonLabel'
|
'downloadButtonLabel'
|
||||||
)}</button>
|
)}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,13 +17,13 @@ module.exports = function(state, emit) {
|
||||||
})}</div>
|
})}</div>
|
||||||
<div id="copy">
|
<div id="copy">
|
||||||
<input id="link" type="url" value="${file.url}" readonly="true"/>
|
<input id="link" type="url" value="${file.url}" readonly="true"/>
|
||||||
<button id="copy-btn" class="btn" onclick=${copyLink}>${state.translate(
|
<button id="copy-btn" class="btn" title="${state.translate(
|
||||||
'copyUrlFormButton'
|
'copyUrlFormButton'
|
||||||
)}</button>
|
)}" onclick=${copyLink}>${state.translate('copyUrlFormButton')}</button>
|
||||||
</div>
|
</div>
|
||||||
<button id="delete-file" class="btn" onclick=${deleteFile}>${state.translate(
|
<button id="delete-file" class="btn" title="${state.translate(
|
||||||
'deleteFileButton'
|
'deleteFileButton'
|
||||||
)}</button>
|
)}" onclick=${deleteFile}>${state.translate('deleteFileButton')}</button>
|
||||||
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
|
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
|
||||||
'sendAnotherFileLink'
|
'sendAnotherFileLink'
|
||||||
)}</a>
|
)}</a>
|
||||||
|
|
|
@ -21,9 +21,9 @@ module.exports = function(state, emit) {
|
||||||
transfer.msg,
|
transfer.msg,
|
||||||
transfer.sizes
|
transfer.sizes
|
||||||
)}</div>
|
)}</div>
|
||||||
<button id="cancel-upload" onclick=${cancel}>${state.translate(
|
<button id="cancel-upload" title="${state.translate(
|
||||||
'uploadingPageCancel'
|
'uploadingPageCancel'
|
||||||
)}</button>
|
)}" onclick=${cancel}>${state.translate('uploadingPageCancel')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -24,9 +24,9 @@ module.exports = function(state, emit) {
|
||||||
)}</em></span>
|
)}</em></span>
|
||||||
<form method="post" action="upload" enctype="multipart/form-data">
|
<form method="post" action="upload" enctype="multipart/form-data">
|
||||||
<label for="file-upload" id="browse" class="${state.config
|
<label for="file-upload" id="browse" class="${state.config
|
||||||
.uploadButtonStyle}">${state.translate(
|
.uploadButtonStyle}" title="${state.translate(
|
||||||
'uploadPageBrowseButton1'
|
'uploadPageBrowseButton1'
|
||||||
)}</label>
|
)}">${state.translate('uploadPageBrowseButton1')}</label>
|
||||||
<input id="file-upload" type="file" name="fileUploaded" onchange=${upload} />
|
<input id="file-upload" type="file" name="fileUploaded" onchange=${upload} />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -278,7 +278,7 @@ a {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="file"] {
|
input[type='file'] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ tbody {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-copy[disabled="disabled"] {
|
.icon-copy[disabled='disabled'] {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ tbody {
|
||||||
|
|
||||||
/* Popup arrow */
|
/* Popup arrow */
|
||||||
.popup .popuptext::after {
|
.popup .popuptext::after {
|
||||||
content: "";
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -11px;
|
bottom: -11px;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
@ -17,7 +17,7 @@
|
||||||
"lint-locales": "node scripts/lint-locales",
|
"lint-locales": "node scripts/lint-locales",
|
||||||
"lint-locales:dev": "npm run lint-locales",
|
"lint-locales:dev": "npm run lint-locales",
|
||||||
"lint-locales:prod": "npm run lint-locales -- --production",
|
"lint-locales:prod": "npm run lint-locales -- --production",
|
||||||
"format": "prettier '!(dist|node_modules|assets)/**/*.js' 'assets/*.css' --single-quote --write",
|
"format": "prettier '**/*.js' 'assets/*.css' --single-quote --write",
|
||||||
"get-prod-locales": "node scripts/get-prod-locales",
|
"get-prod-locales": "node scripts/get-prod-locales",
|
||||||
"get-prod-locales:write": "npm run get-prod-locales -- --write",
|
"get-prod-locales:write": "npm run get-prod-locales -- --write",
|
||||||
"changelog": "github-changes -o mozilla -r send --only-pulls --use-commit-body --no-merges",
|
"changelog": "github-changes -o mozilla -r send --only-pulls --use-commit-body --no-merges",
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
"node": ">=8.2.0"
|
"node": ">=8.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.4",
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-plugin-yo-yoify": "^0.7.0",
|
"babel-plugin-yo-yoify": "^0.7.0",
|
||||||
|
@ -54,10 +54,10 @@
|
||||||
"choo-log": "^7.2.1",
|
"choo-log": "^7.2.1",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
"cross-env": "^5.0.5",
|
"cross-env": "^5.0.5",
|
||||||
"css-loader": "^0.28.5",
|
"css-loader": "^0.28.7",
|
||||||
"css-mqpacker": "^6.0.1",
|
"css-mqpacker": "^6.0.1",
|
||||||
"cssnano": "^3.10.0",
|
"cssnano": "^3.10.0",
|
||||||
"eslint": "^4.5.0",
|
"eslint": "^4.6.1",
|
||||||
"eslint-plugin-mocha": "^4.11.0",
|
"eslint-plugin-mocha": "^4.11.0",
|
||||||
"eslint-plugin-node": "^5.1.1",
|
"eslint-plugin-node": "^5.1.1",
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
|
@ -68,17 +68,17 @@
|
||||||
"github-changes": "^1.1.0",
|
"github-changes": "^1.1.0",
|
||||||
"html-loader": "^0.5.1",
|
"html-loader": "^0.5.1",
|
||||||
"husky": "^0.14.3",
|
"husky": "^0.14.3",
|
||||||
"lint-staged": "^4.0.4",
|
"lint-staged": "^4.1.3",
|
||||||
"mocha": "^3.5.0",
|
"mocha": "^3.5.3",
|
||||||
"nanobus": "^4.2.0",
|
"nanobus": "^4.2.0",
|
||||||
"npm-run-all": "^4.0.2",
|
"npm-run-all": "^4.1.1",
|
||||||
"postcss-loader": "^2.0.6",
|
"postcss-loader": "^2.0.6",
|
||||||
"prettier": "^1.5.3",
|
"prettier": "^1.6.1",
|
||||||
"proxyquire": "^1.8.0",
|
"proxyquire": "^1.8.0",
|
||||||
"raven-js": "^3.17.0",
|
"raven-js": "^3.17.0",
|
||||||
"redis-mock": "^0.20.0",
|
"redis-mock": "^0.20.0",
|
||||||
"require-from-string": "^1.2.1",
|
"require-from-string": "^1.2.1",
|
||||||
"rimraf": "^2.6.1",
|
"rimraf": "^2.6.2",
|
||||||
"selenium-webdriver": "^3.5.0",
|
"selenium-webdriver": "^3.5.0",
|
||||||
"sinon": "^3.2.1",
|
"sinon": "^3.2.1",
|
||||||
"string-hash": "^1.1.3",
|
"string-hash": "^1.1.3",
|
||||||
|
@ -87,15 +87,15 @@
|
||||||
"supertest": "^3.0.0",
|
"supertest": "^3.0.0",
|
||||||
"testpilot-ga": "^0.3.0",
|
"testpilot-ga": "^0.3.0",
|
||||||
"val-loader": "^1.0.2",
|
"val-loader": "^1.0.2",
|
||||||
"webpack": "^3.5.5",
|
"webpack": "^3.5.6",
|
||||||
"webpack-dev-server": "^2.7.1",
|
"webpack-dev-server": "^2.8.0",
|
||||||
"webpack-manifest-plugin": "^1.3.1",
|
"webpack-manifest-plugin": "^1.3.1",
|
||||||
"webpack-unassert-loader": "^1.2.0"
|
"webpack-unassert-loader": "^1.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sdk": "^2.103.0",
|
"aws-sdk": "^2.114.0",
|
||||||
"body-parser": "^1.17.2",
|
"body-parser": "^1.18.1",
|
||||||
"choo": "^6.0.0",
|
"choo": "^6.0.1",
|
||||||
"connect-busboy": "0.0.2",
|
"connect-busboy": "0.0.2",
|
||||||
"convict": "^4.0.0",
|
"convict": "^4.0.0",
|
||||||
"express": "^4.15.4",
|
"express": "^4.15.4",
|
||||||
|
|
|
@ -54,7 +54,9 @@ describe('Server integration tests', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
it('Responds with a 200 when the service is up', function() {
|
it('Responds with a 200 when the service is up', function() {
|
||||||
return request(server).get('/').expect(200);
|
return request(server)
|
||||||
|
.get('/')
|
||||||
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Rejects with a 404 when a file id is not valid', function() {
|
it('Rejects with a 404 when a file id is not valid', function() {
|
||||||
|
@ -89,7 +91,9 @@ describe('Server integration tests', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Responds with a 200 if a file exists', function() {
|
it('Responds with a 200 if a file exists', function() {
|
||||||
return request(server).get('/exists/' + fileId).expect(200);
|
return request(server)
|
||||||
|
.get('/exists/' + fileId)
|
||||||
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Exists in the redis server', function() {
|
it('Exists in the redis server', function() {
|
||||||
|
@ -107,7 +111,9 @@ describe('Server integration tests', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Fails delete if the id is invalid', function() {
|
it('Fails delete if the id is invalid', function() {
|
||||||
return request(server).post('/delete/1').expect(404);
|
return request(server)
|
||||||
|
.post('/delete/1')
|
||||||
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Successfully deletes if the id is valid and the delete token matches', function(
|
it('Successfully deletes if the id is valid and the delete token matches', function(
|
||||||
|
@ -129,7 +135,9 @@ describe('Server integration tests', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Responds with a 404 if a file does not exist', function() {
|
it('Responds with a 404 if a file does not exist', function() {
|
||||||
return request(server).get('/exists/notfound').expect(404);
|
return request(server)
|
||||||
|
.get('/exists/notfound')
|
||||||
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Uploads properly after a delete', function(done) {
|
it('Uploads properly after a delete', function(done) {
|
||||||
|
@ -150,21 +158,25 @@ describe('Server integration tests', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Responds with a 200 for the download page', function() {
|
it('Responds with a 200 for the download page', function() {
|
||||||
return request(server).get('/download/' + fileId).expect(200);
|
return request(server)
|
||||||
|
.get('/download/' + fileId)
|
||||||
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Downloads a file properly', function() {
|
it('Downloads a file properly', function() {
|
||||||
return request(server).get('/assets/download/' + fileId).then(res => {
|
return request(server)
|
||||||
assert(res.header.hasOwnProperty('content-disposition'));
|
.get('/assets/download/' + fileId)
|
||||||
assert(res.header.hasOwnProperty('content-type'));
|
.then(res => {
|
||||||
assert(res.header.hasOwnProperty('content-length'));
|
assert(res.header.hasOwnProperty('content-disposition'));
|
||||||
assert(res.header.hasOwnProperty('x-file-metadata'));
|
assert(res.header.hasOwnProperty('content-type'));
|
||||||
assert.equal(
|
assert(res.header.hasOwnProperty('content-length'));
|
||||||
res.header['content-disposition'],
|
assert(res.header.hasOwnProperty('x-file-metadata'));
|
||||||
'attachment; filename=test_upload.txt'
|
assert.equal(
|
||||||
);
|
res.header['content-disposition'],
|
||||||
assert.equal(res.header['content-type'], 'application/octet-stream');
|
'attachment; filename=test_upload.txt'
|
||||||
});
|
);
|
||||||
|
assert.equal(res.header['content-type'], 'application/octet-stream');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('The file is deleted after one download', function() {
|
it('The file is deleted after one download', function() {
|
||||||
|
|
Loading…
Reference in New Issue