Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Lint step to CircleCI #3642

Merged
merged 8 commits into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ jobs:
path: /tmp/test-results
- store_artifacts:
path: coverage.xml
frontend-lint:
docker:
- image: circleci/node:8
steps:
- checkout
- run: mkdir -p /tmp/test-results/eslint
- run: npm install
- run: npm run lint:ci
- store_test_results:
path: /tmp/test-results
frontend-unit-tests:
docker:
- image: circleci/node:8
Expand All @@ -54,6 +64,7 @@ jobs:
- run: npm install
- run: npm run bundle
- run: npm test
- run: npm run lint
frontend-e2e-tests:
environment:
COMPOSE_FILE: .circleci/docker-compose.cypress.yml
Expand Down Expand Up @@ -105,8 +116,13 @@ workflows:
- python-flake8-tests
- legacy-python-flake8-tests
- backend-unit-tests
- frontend-unit-tests
- frontend-e2e-tests
- frontend-lint
- frontend-unit-tests:
requires:
- frontend-lint
- frontend-e2e-tests:
requires:
- frontend-lint
- build-tarball:
requires:
- backend-unit-tests
Expand Down
24 changes: 8 additions & 16 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,12 @@ plugins:
pep8:
enabled: true
eslint:
enabled: true
channel: "eslint-5"
config:
config: client/.eslintrc.js
checks:
import/no-unresolved:
enabled: false
no-multiple-empty-lines: # TODO: Enable
enabled: false
enabled: false
exclude_patterns:
- "tests/**/*.py"
- "migrations/**/*.py"
- "setup/**/*"
- "bin/**/*"
- "**/node_modules/"
- "client/dist/"
- "**/*.pyc"
- "tests/**/*.py"
- "migrations/**/*.py"
- "setup/**/*"
- "bin/**/*"
- "**/node_modules/"
- "client/dist/"
- "**/*.pyc"
65 changes: 33 additions & 32 deletions client/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
module.exports = {
root: true,
extends: ["airbnb", "plugin:jest/recommended"],
plugins: ["jest", "cypress", "chai-friendly"],
extends: ["airbnb"],
settings: {
"import/resolver": "webpack"
},
parser: "babel-eslint",
env: {
"jest/globals": true,
"cypress/globals": true,
"browser": true,
"node": true
browser: true,
node: true
},
rules: {
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'no-param-reassign': 0,
'no-mixed-operators': 0,
'no-underscore-dangle': 0,
"no-debugger": process.env.NODE_ENV === "production" ? 2 : 0,
"no-param-reassign": 0,
"no-mixed-operators": 0,
"no-underscore-dangle": 0,
"no-use-before-define": ["error", "nofunc"],
"prefer-destructuring": "off",
"prefer-template": "off",
Expand All @@ -27,38 +24,42 @@ module.exports = {
"no-lonely-if": "off",
"consistent-return": "off",
"no-control-regex": "off",
'no-multiple-empty-lines': 'warn',
"no-multiple-empty-lines": "warn",
"no-script-url": "off", // some <a> tags should have href="javascript:void(0)"
'operator-linebreak': 'off',
'react/destructuring-assignment': 'off',
"operator-linebreak": "off",
"react/destructuring-assignment": "off",
"react/jsx-filename-extension": "off",
'react/jsx-one-expression-per-line': 'off',
"react/jsx-one-expression-per-line": "off",
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
'react/jsx-wrap-multilines': 'warn',
'react/no-access-state-in-setstate': 'warn',
"react/jsx-wrap-multilines": "warn",
"react/no-access-state-in-setstate": "warn",
"react/prefer-stateless-function": "warn",
"react/forbid-prop-types": "warn",
"react/prop-types": "warn",
"jsx-a11y/anchor-is-valid": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/label-has-associated-control": ["warn", {
"controlComponents": true
}],
"jsx-a11y/label-has-associated-control": [
"warn",
{
controlComponents: true
}
],
"jsx-a11y/label-has-for": "off",
"jsx-a11y/no-static-element-interactions": "off",
"max-len": ['error', 120, 2, {
ignoreUrls: true,
ignoreComments: false,
ignoreRegExpLiterals: true,
ignoreStrings: true,
ignoreTemplateLiterals: true,
}],
"no-else-return": ["error", {"allowElseIf": true}],
"object-curly-newline": ["error", {"consistent": true}],
// needed for cypress tests
"func-names": "off",
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": 2
"max-len": [
"error",
120,
2,
{
ignoreUrls: true,
ignoreComments: false,
ignoreRegExpLiterals: true,
ignoreStrings: true,
ignoreTemplateLiterals: true
}
],
"no-else-return": ["error", { allowElseIf: true }],
"object-curly-newline": ["error", { consistent: true }]
}
};
7 changes: 7 additions & 0 deletions client/app/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
extends: ["plugin:jest/recommended"],
plugins: ["jest"],
env: {
"jest/globals": true,
},
};
12 changes: 12 additions & 0 deletions client/cypress/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
extends: ["plugin:cypress/recommended"],
plugins: ["cypress", "chai-friendly"],
env: {
"cypress/globals": true
},
rules: {
"func-names": ["error", "never"],
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": 2
}
};
75 changes: 46 additions & 29 deletions client/cypress/integration/dashboard/dashboard_spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const DRAG_PLACEHOLDER_SELECTOR = '.grid-stack-placeholder';

function createNewDashboardByAPI(name) {
return cy.request('POST', 'api/dashboards', { name })
.then(({ body }) => body);
return cy.request('POST', 'api/dashboards', { name }).then(({ body }) => body);
}

function editDashboard() {
Expand All @@ -26,25 +25,28 @@ function addTextboxByAPI(text, dashId) {
},
};

return cy.request('POST', 'api/widgets', data)
.then(({ body }) => {
const id = Cypress._.get(body, 'id');
assert.isDefined(id, 'Widget api call returns widget id');
return `WidgetId${id}`;
});
return cy.request('POST', 'api/widgets', data).then(({ body }) => {
const id = Cypress._.get(body, 'id');
assert.isDefined(id, 'Widget api call returns widget id');
return `WidgetId${id}`;
});
}

function addQueryByAPI(data, shouldPublish = true) {
const merged = Object.assign({
name: 'Test Query',
query: 'select 1',
data_source_id: 1,
options: {
parameters: [],
const merged = Object.assign(
{
name: 'Test Query',
query: 'select 1',
data_source_id: 1,
options: {
parameters: [],
},
schedule: null,
},
schedule: null,
}, data);
data,
);

// eslint-disable-next-line cypress/no-assigning-return-values
const request = cy.request('POST', '/api/queries', merged);
if (shouldPublish) {
request.then(({ body }) => cy.request('POST', `/api/queries/${body.id}`, { is_draft: false }));
Expand Down Expand Up @@ -109,7 +111,9 @@ describe('Dashboard', () => {
it('creates new dashboard', () => {
cy.visit('/dashboards');
cy.getByTestId('CreateButton').click();
cy.get('li[role="menuitem"]').contains('Dashboard').click();
cy.get('li[role="menuitem"]')
.contains('Dashboard')
.click();

cy.server();
cy.route('POST', 'api/dashboards').as('NewDashboard');
Expand Down Expand Up @@ -193,9 +197,13 @@ describe('Dashboard', () => {
cy.visit(this.dashboardUrl);
cy.getByTestId(elTestId)
.within(() => {
cy.get('.widget-menu-regular').click({ force: true }).within(() => {
cy.get('li a').contains('Remove From Dashboard').click({ force: true });
});
cy.get('.widget-menu-regular')
.click({ force: true })
.within(() => {
cy.get('li a')
.contains('Remove From Dashboard')
.click({ force: true });
});
})
.should('not.exist');
});
Expand Down Expand Up @@ -235,18 +243,27 @@ describe('Dashboard', () => {
it('edits textbox', function () {
addTextboxByAPI('Hello World!', this.dashboardId).then((elTestId) => {
cy.visit(this.dashboardUrl);
cy.getByTestId(elTestId).as('textboxEl')
cy.getByTestId(elTestId)
.as('textboxEl')
.within(() => {
cy.get('.widget-menu-regular').click({ force: true }).within(() => {
cy.get('li a').contains('Edit').click({ force: true });
});
cy.get('.widget-menu-regular')
.click({ force: true })
.within(() => {
cy.get('li a')
.contains('Edit')
.click({ force: true });
});
});

const newContent = '[edited]';
cy.get('edit-text-box').should('exist').within(() => {
cy.get('textarea').clear().type(newContent);
cy.contains('button', 'Save').click();
});
cy.get('edit-text-box')
.should('exist')
.within(() => {
cy.get('textarea')
.clear()
.type(newContent);
cy.contains('button', 'Save').click();
});

cy.get('@textboxEl').should('contain', newContent);
});
Expand All @@ -269,7 +286,7 @@ describe('Dashboard', () => {

describe('Draggable', () => {
describe('Grid snap', () => {
beforeEach(function () {
beforeEach(() => {
editDashboard();
});

Expand Down
4 changes: 2 additions & 2 deletions client/cypress/integration/user/login_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Login', () => {
it('greets the user and take a screenshot', () => {
cy.contains('h3', 'Login to Redash');

cy.wait(1000);
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
cy.percySnapshot('Login');
});

Expand All @@ -24,7 +24,7 @@ describe('Login', () => {
cy.title().should('eq', 'Redash');
cy.contains('Example Admin');

cy.wait(1000);
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
cy.percySnapshot('Homepage');
});
});
2 changes: 1 addition & 1 deletion client/cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import '@percy/cypress'; // eslint-disable-line import/no-extraneous-dependencies
import '@percy/cypress'; // eslint-disable-line import/no-extraneous-dependencies, import/no-unresolved

Cypress.Commands.add('login', (email = 'admin@redash.io', password = 'password') => cy.request({
url: '/login',
Expand Down
Loading