Skip to content

Commit

Permalink
updated config managment
Browse files Browse the repository at this point in the history
  • Loading branch information
Rlyehan committed May 14, 2023
1 parent 5263773 commit ce3e5ea
Show file tree
Hide file tree
Showing 37 changed files with 1,359 additions and 20 deletions.
55 changes: 55 additions & 0 deletions .cylintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"testDirectory": "./sample_tests",
"rules": [
{
"id": "no-hardcoded-wait",
"description": "Disallow the use of hardcoded wait times.",
"enabled": true
},
{
"id": "use-data-attributes",
"description": "Use data-* attributes for selectors.",
"enabled": true
},
{
"id": "avoid-tag-class-id-selectors",
"description": "Avoid using tag, class, or ID selectors.",
"enabled": true
},
{
"id": "avoid-command-return-value-assignments",
"description": "Avoid assigning the return value of Cypress commands with const, let, or var.",
"enabled": true
},
{
"id": "no-external-site-visit",
"description": "Avoid visiting external sites or servers you do not control.",
"enabled": true
},
{
"id": "no-test-state-dependence",
"description": "Avoid having tests rely on the state of previous tests.",
"enabled": true
},
{
"id": "no-web-server-in-cypress",
"description": "Avoid starting a web server from within Cypress scripts with cy.exec() or cy.task().",
"enabled": true
},
{
"id": "at-least-one-assertion",
"description": "There should be at least one assertion in each it block.",
"enabled": true
},
{
"id": "use-base-url",
"description": "Use base URL from config instead of full URLs.",
"enabled": true
},
{
"id": "no-hardcoded-credentials",
"description": "Avoid using hardcoded credentials in tests, use environment variables or fixtures instead.",
"enabled": true
}
]
}
8 changes: 8 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# ignore TypeScript source files
src/

# ignore tests
**/*.spec.ts

# ignore TypeScript compiler output directory
dist/
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
"main": "src/main.ts",
"repository": {
"type": "git",
"url": "https://github.com/yourusername/cy-lint.git"
"url": "https://github.com/Rlyehan/cy-lint.git"
},
"keywords": [
"cypress",
"lint",
"testing",
"best-practices"
],
"author": "Maximilian Huber max_hub@gmx.net",
"author": "Maximilian Huber",
"license": "Apache License Version 2.0",
"bugs": {
"url": "https://github.com/yourusername/cy-lint/issues"
"url": "https://github.com/Rlyehan/cy-lint/issues"
},
"homepage": "https://github.com/yourusername/cy-lint#readme",
"homepage": "https://github.com/Rlyehan/cy-lint#readme",
"scripts": {
"start": "ts-node src/main.ts",
"build": "tsc",
"test": "jest",
"lint": "eslint . --ext .ts",
"format": "prettier --write .",
Expand Down
4 changes: 2 additions & 2 deletions report.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"timestamp": "2023-05-02T12:48:04.170Z",
"timestamp": "2023-05-12T15:45:01.421Z",
"violations": [
{
"filepath": "sample_tests/example.cy.ts",
Expand Down Expand Up @@ -92,4 +92,4 @@
"description": "There should be at least one assertion in each it block"
}
]
}
}
9 changes: 9 additions & 0 deletions sample_tests/example.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";
// sample_tests/example.spec.ts
describe("Sample test suite", () => {
it("Sample test case", () => {
cy.visit("/");
cy.wait(1000);
cy.get("#element");
});
});
28 changes: 28 additions & 0 deletions sample_tests/example2.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";
describe("Violations of all rules", () => {
it("State dependence violation", () => {
cy.visit("/users/new");
cy.get('[data-testid="first-name"]').type("Johnny");
cy.get('[data-testid="last-name"]').type("Appleseed");
cy.get("form").submit();
});
it("No assertion violation", () => {
cy.visit("/users");
// No assertions here
});
describe("Base URL violation", () => {
it("does something", () => {
cy.visit("https://example.com/users");
});
});
describe("Hardcoded credentials violation", () => {
beforeEach(() => {
cy.visit("/login");
cy.get("#username").type("test_user");
cy.get("#password").type("test_password");
});
it("does something with hardcoded credentials", () => {
// Test code here
});
});
});
43 changes: 43 additions & 0 deletions src/__tests__/atleastoneAssertion.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const atLeastOneAssertion_1 = require("../rules/implementations/atLeastOneAssertion");
const test_utils_1 = require("../test_utils");
describe("atLeastOneAssertionPerItBlock rule", () => {
it("should pass when there is at least one assertion in each it block", () => {
const code = `
describe('my form', () => {
it('displays form validation', () => {
cy.get('.error').should('be.visible');
});
it('can submit a valid form', () => {
expect(true).toBe(true);
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, atLeastOneAssertion_1.atLeastOneAssertion)(node));
});
expect(violations.length).toBe(0);
});
it("should fail when there is no assertion in an it block", () => {
const code = `
describe('my form', () => {
it('displays form validation', () => {
cy.get('.error').should('be.visible');
});
it('can submit a valid form', () => {
// Missing assertion
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, atLeastOneAssertion_1.atLeastOneAssertion)(node));
});
expect(violations.length).toBe(1);
expect(violations[0].description).toBe("There should be at least one assertion in each it block");
});
});
37 changes: 37 additions & 0 deletions src/__tests__/avoidCommandReturnValueAssignments.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const avoidCommandReturnValueAssignments_1 = require("../rules/implementations/avoidCommandReturnValueAssignments");
const test_utils_1 = require("../test_utils");
describe("avoidCommandReturnValueAssignments rule", () => {
it("should pass when no command return value assignments are present", () => {
const code = `
describe('Test without command return value assignments', () => {
it('does something', () => {
cy.visit('/users');
cy.get('#username').type('test_user');
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, avoidCommandReturnValueAssignments_1.avoidCommandReturnValueAssignments)(node));
});
expect(violations.length).toBe(0);
});
it("should fail when command return value assignments are present", () => {
const code = `
describe('Test with command return value assignments', () => {
it('does something', () => {
const element = cy.get('#username');
element.type('test_user');
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, avoidCommandReturnValueAssignments_1.avoidCommandReturnValueAssignments)(node));
});
expect(violations.length).toBe(1);
expect(violations[0].description).toBe("Avoid assigning the return value of Cypress commands with const, let, or var");
});
});
39 changes: 39 additions & 0 deletions src/__tests__/avoidTagClassIdSelectors.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const avoidTagClassId_1 = require("../rules/implementations/avoidTagClassId");
const test_utils_1 = require("../test_utils");
describe("avoidTagClassIdSelectors rule", () => {
it("should pass when no tag, class, or ID selectors are used", () => {
const code = `
describe('Test without tag, class, or ID selectors', () => {
it('does something', () => {
cy.get('[data-testid="submit-button"]').click();
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, avoidTagClassId_1.avoidTagClassIdSelectors)(node));
});
expect(violations.length).toBe(0);
});
it("should fail when tag, class, or ID selectors are used", () => {
const code = `
describe('Test with tag, class, or ID selectors', () => {
it('does something', () => {
cy.get('#submit-button').click();
cy.get('.submit-button').click();
cy.get('button').click();
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, avoidTagClassId_1.avoidTagClassIdSelectors)(node));
});
expect(violations.length).toBe(3);
expect(violations[0].description).toBe("Avoid using tag, class, or ID selectors. Found: '#submit-button'");
expect(violations[1].description).toBe("Avoid using tag, class, or ID selectors. Found: '.submit-button'");
expect(violations[2].description).toBe("Avoid using tag, class, or ID selectors. Found: 'button'");
});
});
35 changes: 35 additions & 0 deletions src/__tests__/noExternalSiteVisit.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const noExternalSiteVisit_1 = require("../rules/implementations/noExternalSiteVisit");
const test_utils_1 = require("../test_utils");
describe("noExternalSiteVisit rule", () => {
it("should pass when no external site visit is used", () => {
const code = `
describe('Test without external site visit', () => {
it('does something', () => {
cy.visit('/local-path');
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, noExternalSiteVisit_1.noExternalSiteVisit)(node));
});
expect(violations.length).toBe(0);
});
it("should fail when an external site visit is used", () => {
const code = `
describe('Test with external site visit', () => {
it('does something', () => {
cy.visit('https://example.com');
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, noExternalSiteVisit_1.noExternalSiteVisit)(node));
});
expect(violations.length).toBe(1);
expect(violations[0].description).toBe("Avoid visiting external sites or servers you do not control");
});
});
48 changes: 48 additions & 0 deletions src/__tests__/noHardcodedCredentials.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const noHardcodedCredentials_1 = require("../rules/implementations/noHardcodedCredentials");
const test_utils_1 = require("../test_utils");
describe("noHardcodedCredentials rule", () => {
it("should pass when no hardcoded credentials are present", () => {
const code = `
describe('login', () => {
beforeEach(() => {
cy.visit('/login');
});
it('logs in successfully', () => {
cy.get('#username').type(Cypress.env('USERNAME'));
cy.get('#password').type(Cypress.env('PASSWORD'));
cy.get('#login').click();
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, noHardcodedCredentials_1.noHardcodedCredentials)(node));
});
expect(violations.length).toBe(0);
});
it("should fail when hardcoded credentials are present", () => {
const code = `
describe('login', () => {
beforeEach(() => {
cy.visit('/login');
});
it('logs in successfully', () => {
cy.get('#username').type('admin');
cy.get('#password').type('password123');
cy.get('#login').click();
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, noHardcodedCredentials_1.noHardcodedCredentials)(node));
});
expect(violations.length).toBe(2);
expect(violations[0].description).toBe("Avoid using hardcoded credentials in tests, use environment variables or fixtures instead");
expect(violations[1].description).toBe("Avoid using hardcoded credentials in tests, use environment variables or fixtures instead");
});
});
35 changes: 35 additions & 0 deletions src/__tests__/noHardcodedWait.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const noHardCodeWait_1 = require("../rules/implementations/noHardCodeWait");
const test_utils_1 = require("../test_utils");
describe("noHardcodedWait rule", () => {
it("should pass when no hardcoded wait is used", () => {
const code = `
describe('Test without hardcoded wait', () => {
it('does something', () => {
cy.get('.element').should('be.visible');
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, noHardCodeWait_1.noHardcodedWait)(node));
});
expect(violations.length).toBe(0);
});
it("should fail when a hardcoded wait is used", () => {
const code = `
describe('Test with hardcoded wait', () => {
it('does something', () => {
cy.wait(500);
});
});
`;
const violations = [];
(0, test_utils_1.traverseAst)(code, (node) => {
violations.push(...(0, noHardCodeWait_1.noHardcodedWait)(node));
});
expect(violations.length).toBe(1);
expect(violations[0].description).toBe("Avoid using hardcoded wait times");
});
});
Loading

0 comments on commit ce3e5ea

Please sign in to comment.