Merge pull request #6304 from matrix-org/dbkr/tests_lint

Fix Test Linting
This commit is contained in:
David Baker 2021-07-01 23:20:45 +01:00 committed by GitHub
commit bd470f8897
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 487 deletions

View file

@ -1,15 +0,0 @@
# autogenerated file: run scripts/generate-eslint-error-ignore-file to update.
src/Markdown.js
src/NodeAnimator.js
src/components/structures/RoomDirectory.js
src/components/views/rooms/MemberList.js
src/utils/DMRoomMap.js
src/utils/MultiInviter.js
test/components/structures/MessagePanel-test.js
test/components/views/dialogs/InteractiveAuthDialog-test.js
test/mock-clock.js
src/component-index.js
test/end-to-end-tests/node_modules/
test/end-to-end-tests/element/
test/end-to-end-tests/synapse/

View file

@ -45,7 +45,7 @@
"start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"yarn start:build\" \"yarn reskindex:watch\"",
"start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
"lint": "yarn lint:types && yarn lint:js && yarn lint:style",
"lint:js": "eslint --max-warnings 0 --ignore-path .eslintignore.errorfiles src test",
"lint:js": "eslint --max-warnings 0 src test",
"lint:types": "tsc --noEmit --jsx react",
"lint:style": "stylelint 'res/css/**/*.scss'",
"test": "jest",

View file

@ -1,23 +0,0 @@
#!/bin/sh
#
# generates .eslintignore.errorfiles to list the files which have errors in,
# so that they can be ignored in future automated linting.
out=.eslintignore.errorfiles
cd `dirname $0`/..
echo "generating $out"
{
cat <<EOF
# autogenerated file: run scripts/generate-eslint-error-ignore-file to update.
EOF
./node_modules/.bin/eslint -f json src test |
jq -r '.[] | select((.errorCount + .warningCount) > 0) | .filePath' |
sed -e 's/.*matrix-react-sdk\///';
} > "$out"
# also append rules from eslintignore file
cat .eslintignore >> $out

View file

@ -1,6 +1,6 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019, 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -26,11 +26,11 @@ import { EventEmitter } from "events";
import sdk from '../../skinned-sdk';
const MessagePanel = sdk.getComponent('structures.MessagePanel');
import {MatrixClientPeg} from '../../../src/MatrixClientPeg';
import { MatrixClientPeg } from '../../../src/MatrixClientPeg';
import Matrix from 'matrix-js-sdk';
const test_utils = require('../../test-utils');
const mockclock = require('../../mock-clock');
const TestUtilsMatrix = require('../../test-utils');
import FakeTimers from '@sinonjs/fake-timers';
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
import { configure, mount } from "enzyme";
@ -72,14 +72,14 @@ class WrappedMessagePanel extends React.Component {
}
describe('MessagePanel', function() {
const clock = mockclock.clock();
let clock = null;
const realSetTimeout = window.setTimeout;
const events = mkEvents();
beforeEach(function() {
test_utils.stubClient();
TestUtilsMatrix.stubClient();
client = MatrixClientPeg.get();
client.credentials = {userId: '@me:here'};
client.credentials = { userId: '@me:here' };
// HACK: We assume all settings want to be disabled
SettingsStore.getValue = jest.fn((arg) => {
@ -90,14 +90,17 @@ describe('MessagePanel', function() {
});
afterEach(function() {
clock.uninstall();
if (clock) {
clock.uninstall();
clock = null;
}
});
function mkEvents() {
const events = [];
const ts0 = Date.now();
for (let i = 0; i < 10; i++) {
events.push(test_utils.mkMessage(
events.push(TestUtilsMatrix.mkMessage(
{
event: true, room: "!room:id", user: "@user:id",
ts: ts0 + i * 1000,
@ -111,7 +114,7 @@ describe('MessagePanel', function() {
const events = [];
const ts0 = Date.parse('09 May 2004 00:12:00 GMT');
for (let i = 0; i < 10; i++) {
events.push(test_utils.mkMessage(
events.push(TestUtilsMatrix.mkMessage(
{
event: true, room: "!room:id", user: "@user:id",
ts: ts0 + i * 1000,
@ -120,7 +123,6 @@ describe('MessagePanel', function() {
return events;
}
// make a collection of events with some member events that should be collapsed
// with a MemberEventListSummary
function mkMelsEvents() {
@ -128,13 +130,13 @@ describe('MessagePanel', function() {
const ts0 = Date.now();
let i = 0;
events.push(test_utils.mkMessage({
events.push(TestUtilsMatrix.mkMessage({
event: true, room: "!room:id", user: "@user:id",
ts: ts0 + ++i * 1000,
}));
for (i = 0; i < 10; i++) {
events.push(test_utils.mkMembership({
events.push(TestUtilsMatrix.mkMembership({
event: true, room: "!room:id", user: "@user:id",
target: {
userId: "@user:id",
@ -151,7 +153,7 @@ describe('MessagePanel', function() {
}));
}
events.push(test_utils.mkMessage({
events.push(TestUtilsMatrix.mkMessage({
event: true, room: "!room:id", user: "@user:id",
ts: ts0 + ++i*1000,
}));
@ -167,7 +169,7 @@ describe('MessagePanel', function() {
let i = 0;
for (i = 0; i < 10; i++) {
events.push(test_utils.mkMembership({
events.push(TestUtilsMatrix.mkMembership({
event: true, room: "!room:id", user: "@user:id",
target: {
userId: "@user:id",
@ -189,8 +191,8 @@ describe('MessagePanel', function() {
// A list of room creation, encryption, and invite events.
function mkCreationEvents() {
const mkEvent = test_utils.mkEvent;
const mkMembership = test_utils.mkMembership;
const mkEvent = TestUtilsMatrix.mkEvent;
const mkMembership = TestUtilsMatrix.mkMembership;
const roomId = "!someroom";
const alice = "@alice:example.org";
const ts0 = Date.now();
@ -363,8 +365,7 @@ describe('MessagePanel', function() {
it('shows a ghost read-marker when the read-marker moves', function(done) {
// fake the clock so that we can test the velocity animation.
clock.install();
clock.mockDate();
clock = FakeTimers.install();
const parentDiv = document.createElement('div');

View file

@ -20,10 +20,10 @@ import ReactTestUtils from 'react-dom/test-utils';
import MatrixReactTestUtils from 'matrix-react-test-utils';
import sdk from '../../../skinned-sdk';
import {MatrixClientPeg} from '../../../../src/MatrixClientPeg';
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
import * as test_utils from '../../../test-utils';
import {sleep} from "../../../../src/utils/promise";
import * as TestUtilsMatrix from '../../../test-utils';
import { sleep } from "../../../../src/utils/promise";
const InteractiveAuthDialog = sdk.getComponent(
'views.dialogs.InteractiveAuthDialog',
@ -33,7 +33,7 @@ describe('InteractiveAuthDialog', function() {
let parentDiv;
beforeEach(function() {
test_utils.stubClient();
TestUtilsMatrix.stubClient();
parentDiv = document.createElement('div');
document.body.appendChild(parentDiv);
});
@ -45,11 +45,11 @@ describe('InteractiveAuthDialog', function() {
it('Should successfully complete a password flow', function() {
const onFinished = jest.fn();
const doRequest = jest.fn().mockResolvedValue({a: 1});
const doRequest = jest.fn().mockResolvedValue({ a: 1 });
// tell the stub matrixclient to return a real userid
const client = MatrixClientPeg.get();
client.credentials = {userId: "@user:id"};
client.credentials = { userId: "@user:id" };
const dlg = ReactDOM.render(
<InteractiveAuthDialog
@ -57,7 +57,7 @@ describe('InteractiveAuthDialog', function() {
authData={{
session: "sess",
flows: [
{"stages": ["m.login.password"]},
{ "stages": ["m.login.password"] },
],
}}
makeRequest={doRequest}
@ -105,7 +105,7 @@ describe('InteractiveAuthDialog', function() {
return sleep(1);
}).then(sleep(1)).then(() => {
expect(onFinished).toBeCalledTimes(1);
expect(onFinished).toBeCalledWith(true, {a: 1});
expect(onFinished).toBeCalledWith(true, { a: 1 });
});
});
});

View file

@ -1,421 +0,0 @@
/*
Copyright (c) 2008-2015 Pivotal Labs
Copyright 2019 The Matrix.org Foundation C.I.C.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* This is jasmine's implementation of a mock clock, lifted from the depths of
* jasmine-core and exposed as a standalone module. The interface is just the
* same as that of jasmine.clock. For example:
*
* var mock_clock = require("../../mock-clock").clock();
* mock_clock.install();
* setTimeout(function() {
* timerCallback();
* }, 100);
*
* expect(timerCallback).not.toHaveBeenCalled();
* mock_clock.tick(101);
* expect(timerCallback).toHaveBeenCalled();
*
* mock_clock.uninstall();
*
*
* The reason for C&Ping jasmine's clock here is that jasmine itself is
* difficult to webpack, and we don't really want all of it. Sinon also has a
* mock-clock implementation, but again, it is difficult to webpack.
*/
const j$ = {};
j$.Clock = function() {
function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
let self = this,
realTimingFunctions = {
setTimeout: global.setTimeout,
clearTimeout: global.clearTimeout,
setInterval: global.setInterval,
clearInterval: global.clearInterval,
},
fakeTimingFunctions = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
},
installed = false,
delayedFunctionScheduler,
timer;
self.install = function() {
if(!originalTimingFunctionsIntact()) {
throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
}
replace(global, fakeTimingFunctions);
timer = fakeTimingFunctions;
delayedFunctionScheduler = delayedFunctionSchedulerFactory();
installed = true;
return self;
};
self.uninstall = function() {
delayedFunctionScheduler = null;
mockDate.uninstall();
replace(global, realTimingFunctions);
timer = realTimingFunctions;
installed = false;
};
self.withMock = function(closure) {
this.install();
try {
closure();
} finally {
this.uninstall();
}
};
self.mockDate = function(initialDate) {
mockDate.install(initialDate);
};
self.setTimeout = function(fn, delay, params) {
if (legacyIE()) {
if (arguments.length > 2) {
throw new Error('IE < 9 cannot support extra params to setTimeout without a polyfill');
}
return timer.setTimeout(fn, delay);
}
return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
};
self.setInterval = function(fn, delay, params) {
if (legacyIE()) {
if (arguments.length > 2) {
throw new Error('IE < 9 cannot support extra params to setInterval without a polyfill');
}
return timer.setInterval(fn, delay);
}
return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
};
self.clearTimeout = function(id) {
return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
};
self.clearInterval = function(id) {
return Function.prototype.call.apply(timer.clearInterval, [global, id]);
};
self.tick = function(millis) {
if (installed) {
mockDate.tick(millis);
delayedFunctionScheduler.tick(millis);
} else {
throw new Error('Mock clock is not installed, use jasmine.clock().install()');
}
};
return self;
function originalTimingFunctionsIntact() {
return global.setTimeout === realTimingFunctions.setTimeout &&
global.clearTimeout === realTimingFunctions.clearTimeout &&
global.setInterval === realTimingFunctions.setInterval &&
global.clearInterval === realTimingFunctions.clearInterval;
}
function legacyIE() {
//if these methods are polyfilled, apply will be present
return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
}
function replace(dest, source) {
for (const prop in source) {
dest[prop] = source[prop];
}
}
function setTimeout(fn, delay) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
}
function clearTimeout(id) {
return delayedFunctionScheduler.removeFunctionWithId(id);
}
function setInterval(fn, interval) {
return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
}
function clearInterval(id) {
return delayedFunctionScheduler.removeFunctionWithId(id);
}
function argSlice(argsObj, n) {
return Array.prototype.slice.call(argsObj, n);
}
}
return Clock;
}();
j$.DelayedFunctionScheduler = function() {
function DelayedFunctionScheduler() {
const self = this;
const scheduledLookup = [];
const scheduledFunctions = {};
let currentTime = 0;
let delayedFnCount = 0;
self.tick = function(millis) {
millis = millis || 0;
const endTime = currentTime + millis;
runScheduledFunctions(endTime);
currentTime = endTime;
};
self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
let f;
if (typeof(funcToCall) === 'string') {
/* jshint evil: true */
f = function() { return eval(funcToCall); };
/* jshint evil: false */
} else {
f = funcToCall;
}
millis = millis || 0;
timeoutKey = timeoutKey || ++delayedFnCount;
runAtMillis = runAtMillis || (currentTime + millis);
const funcToSchedule = {
runAtMillis: runAtMillis,
funcToCall: f,
recurring: recurring,
params: params,
timeoutKey: timeoutKey,
millis: millis,
};
if (runAtMillis in scheduledFunctions) {
scheduledFunctions[runAtMillis].push(funcToSchedule);
} else {
scheduledFunctions[runAtMillis] = [funcToSchedule];
scheduledLookup.push(runAtMillis);
scheduledLookup.sort(function(a, b) {
return a - b;
});
}
return timeoutKey;
};
self.removeFunctionWithId = function(timeoutKey) {
for (const runAtMillis in scheduledFunctions) {
const funcs = scheduledFunctions[runAtMillis];
const i = indexOfFirstToPass(funcs, function(func) {
return func.timeoutKey === timeoutKey;
});
if (i > -1) {
if (funcs.length === 1) {
delete scheduledFunctions[runAtMillis];
deleteFromLookup(runAtMillis);
} else {
funcs.splice(i, 1);
}
// intervals get rescheduled when executed, so there's never more
// than a single scheduled function with a given timeoutKey
break;
}
}
};
return self;
function indexOfFirstToPass(array, testFn) {
let index = -1;
for (let i = 0; i < array.length; ++i) {
if (testFn(array[i])) {
index = i;
break;
}
}
return index;
}
function deleteFromLookup(key) {
const value = Number(key);
const i = indexOfFirstToPass(scheduledLookup, function(millis) {
return millis === value;
});
if (i > -1) {
scheduledLookup.splice(i, 1);
}
}
function reschedule(scheduledFn) {
self.scheduleFunction(scheduledFn.funcToCall,
scheduledFn.millis,
scheduledFn.params,
true,
scheduledFn.timeoutKey,
scheduledFn.runAtMillis + scheduledFn.millis);
}
function forEachFunction(funcsToRun, callback) {
for (let i = 0; i < funcsToRun.length; ++i) {
callback(funcsToRun[i]);
}
}
function runScheduledFunctions(endTime) {
if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
return;
}
do {
currentTime = scheduledLookup.shift();
const funcsToRun = scheduledFunctions[currentTime];
delete scheduledFunctions[currentTime];
forEachFunction(funcsToRun, function(funcToRun) {
if (funcToRun.recurring) {
reschedule(funcToRun);
}
});
forEachFunction(funcsToRun, function(funcToRun) {
funcToRun.funcToCall.apply(null, funcToRun.params || []);
});
} while (scheduledLookup.length > 0 &&
// checking first if we're out of time prevents setTimeout(0)
// scheduled in a funcToRun from forcing an extra iteration
currentTime !== endTime &&
scheduledLookup[0] <= endTime);
}
}
return DelayedFunctionScheduler;
}();
j$.MockDate = function() {
function MockDate(global) {
const self = this;
let currentTime = 0;
if (!global || !global.Date) {
self.install = function() {};
self.tick = function() {};
self.uninstall = function() {};
return self;
}
const GlobalDate = global.Date;
self.install = function(mockDate) {
if (mockDate instanceof GlobalDate) {
currentTime = mockDate.getTime();
} else {
currentTime = new GlobalDate().getTime();
}
global.Date = FakeDate;
};
self.tick = function(millis) {
millis = millis || 0;
currentTime = currentTime + millis;
};
self.uninstall = function() {
currentTime = 0;
global.Date = GlobalDate;
};
createDateProperties();
return self;
function FakeDate() {
switch(arguments.length) {
case 0:
return new GlobalDate(currentTime);
case 1:
return new GlobalDate(arguments[0]);
case 2:
return new GlobalDate(arguments[0], arguments[1]);
case 3:
return new GlobalDate(arguments[0], arguments[1], arguments[2]);
case 4:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
case 5:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4]);
case 6:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4], arguments[5]);
default:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4], arguments[5], arguments[6]);
}
}
function createDateProperties() {
FakeDate.prototype = GlobalDate.prototype;
FakeDate.now = function() {
if (GlobalDate.now) {
return currentTime;
} else {
throw new Error('Browser does not support Date.now()');
}
};
FakeDate.toSource = GlobalDate.toSource;
FakeDate.toString = GlobalDate.toString;
FakeDate.parse = GlobalDate.parse;
FakeDate.UTC = GlobalDate.UTC;
}
}
return MockDate;
}();
const _clock = new j$.Clock(global, function() { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
export function clock() {
return _clock;
}