mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 00:45:19 +00:00
Complete removal of Cypress (#13389)
Remove the last of the dependencies and configuration around Cypress since we no longer use it for testing.
This commit is contained in:
parent
19a5ae6465
commit
4ecc7db6d6
@ -5,7 +5,6 @@ module.exports = {
|
||||
"plugin:jest/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:cypress/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:storybook/recommended",
|
||||
],
|
||||
@ -83,13 +82,6 @@ module.exports = {
|
||||
"jsx-a11y/anchor-has-content": "off",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["cypress/**/*.ts"],
|
||||
// Set to turn off jest linting error on cypress library
|
||||
rules: {
|
||||
"jest/valid-expect": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -44,7 +44,6 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
~/.cache/Cypress
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-modules-
|
||||
@ -78,7 +77,6 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
~/.cache/Cypress
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-modules-
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -41,11 +41,6 @@ helm-temp
|
||||
#editors
|
||||
.idea
|
||||
|
||||
# Cypress e2e testing
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
cypress/downloads
|
||||
|
||||
# Fleet local development DB backups
|
||||
backup.sql.gz
|
||||
|
||||
|
@ -28,11 +28,6 @@ tmp/
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# Cypress e2e testing
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
cypress/downloads
|
||||
|
||||
# fleetdm.com website (uses its own formatting conventions)
|
||||
website/
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
# Cypress testing
|
||||
|
||||
Cypress tests are designed solely for end-to-end testing. If this is your first time developing or running end-to-end tests, [Fleet testing documentation](../docs/Contributing/Testing-and-local-development.md) includes git instructions for test preparation and running tests.
|
||||
|
||||
## Fleet Cypress directories
|
||||
|
||||
### Integration directory
|
||||
|
||||
Cypress tests the integration of [entire features](integration/all/app) of the app.
|
||||
|
||||
With the roll out of teams, Cypress tests the user interface of each role of a user on the Premium Tier ([Fleet Premium Documentation](integration/premium/README.md)) and Free Tier ([Fleet Free Documentation](integration/free/README.md)).
|
||||
|
||||
### Support directory
|
||||
|
||||
[Commands](support/commands.ts) that are shared across tests are located in the support directory.
|
||||
|
||||
## Opening Cypress locally
|
||||
|
||||
To open simply run:
|
||||
|
||||
`yarn cypress:open`
|
||||
|
||||
This will open up cypress locally and
|
||||
allow you to view the current test suite, as well as start writing new tests.
|
||||
|
||||
## Building best practices
|
||||
|
||||
As much as possible, build from a user's perspective. Use `.within` cypress command as needed to scope a command within a specific element (e.g. table, nav).
|
||||
|
||||
As much as possible, assert that the code is only selecting 1 item or that the final assertion is the appropriate count.
|
||||
|
||||
### Prioritization of selecting elements
|
||||
|
||||
1. By **element tag** using elements (e.g. buttons), we can target text within. Confirm what the user is seeing with target text. If this is not specific enough, add on Role.
|
||||
2. By **role** using default or explicitly assigned roles of elements. If this is not specific enough, add on element class.
|
||||
3. By **element class** is least preferred as it does not follow a user's perspective. Occasionally this may be the only option. If that is the case, prioritize using the class name that specifies what the element is doing.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Fleet testing documentation](../docs/Contributing/Testing-and-local-development.md)
|
||||
- [Cypress documentation](https://docs.cypress.io/api/table-of-contents)
|
||||
- [React testing-library query documentation](https://testing-library.com/docs/queries/about/)
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"baseUrl": "https://localhost:8642",
|
||||
"fixturesFolder": false,
|
||||
"experimentalSessionSupport": true,
|
||||
"testFiles": "{all,free}/**/*.spec.ts",
|
||||
"retries": {
|
||||
"runMode": 2,
|
||||
"openMode": 0
|
||||
},
|
||||
"video": false,
|
||||
"videoUploadOnPasses": false,
|
||||
"defaultCommandTimeout": 8000
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"baseUrl": "https://localhost:8642",
|
||||
"fixturesFolder": false,
|
||||
"experimentalSessionSupport": true,
|
||||
"testFiles": "{all,premium}/**/*.spec.ts",
|
||||
"retries": {
|
||||
"runMode": 2,
|
||||
"openMode": 0
|
||||
},
|
||||
"video": false,
|
||||
"videoUploadOnPasses": false,
|
||||
"defaultCommandTimeout": 8000
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
|
||||
const {
|
||||
GOOD_PASSWORD,
|
||||
BAD_PASSWORD_LENGTH,
|
||||
BAD_PASSWORD_NO_NUMBER,
|
||||
BAD_PASSWORD_NO_SYMBOL,
|
||||
} = CONSTANTS;
|
||||
|
||||
describe("Activate user flow", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.setupSMTP();
|
||||
cy.viewport(1600, 900);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Users settings page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1600, 900);
|
||||
cy.visit("/settings/organization");
|
||||
cy.getAttached(".component__tabs-wrapper").within(() => {
|
||||
cy.findByRole("tab", { name: /^users$/i }).click();
|
||||
});
|
||||
});
|
||||
it("invites and activates a user", () => {
|
||||
cy.getAttached(".user-management").within(() => {
|
||||
cy.contains("button", /create user/i).click();
|
||||
});
|
||||
cy.getAttached(".create-user-modal").within(() => {
|
||||
cy.findByLabelText(/name/i).click().type("Ash Ketchum");
|
||||
cy.findByLabelText(/email/i).click().type("ash@example.com");
|
||||
cy.getAttached(".create-user-form__new-user-radios").within(() => {
|
||||
cy.findByRole("radio", { name: "Invite user" }).parent().click();
|
||||
});
|
||||
cy.findByRole("button", { name: /^create$/i }).click();
|
||||
});
|
||||
// Ensures the email has been delivered
|
||||
cy.wait(3000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.logout();
|
||||
// Retrieves user invite in email
|
||||
const inviteLink = { url: "" };
|
||||
const regex = /\/login\/invites\/[a-zA-Z0-9=?%&@._-]*/gm;
|
||||
cy.getEmails().then((response) => {
|
||||
expect(response.body.items[0].To[0]).to.have.property("Domain");
|
||||
expect(response.body.items[0].To[0].Mailbox).to.equal("ash");
|
||||
expect(response.body.items[0].To[0].Domain).to.equal("example.com");
|
||||
expect(response.body.items[0].From.Mailbox).to.equal("fleet");
|
||||
expect(response.body.items[0].From.Domain).to.equal("example.com");
|
||||
const match = response.body.items[0].Content.Body.match(regex);
|
||||
inviteLink.url = match[0];
|
||||
});
|
||||
// Activates user
|
||||
cy.visit(inviteLink);
|
||||
cy.getAttached(".confirm-invite-page").within(() => {
|
||||
cy.findByLabelText(/full name/i)
|
||||
.clear()
|
||||
.type("Ash Ketchum");
|
||||
cy.findByLabelText(/^password$/i)
|
||||
.click()
|
||||
.type(BAD_PASSWORD_LENGTH);
|
||||
cy.findByLabelText(/confirm password/i)
|
||||
.click()
|
||||
.type(BAD_PASSWORD_LENGTH);
|
||||
cy.findByRole("button", { name: /submit/i }).click();
|
||||
});
|
||||
cy.findByText(/password does not meet required criteria/i).should(
|
||||
"exist"
|
||||
);
|
||||
cy.getAttached("#password").clear().type(BAD_PASSWORD_NO_NUMBER);
|
||||
cy.getAttached("#password_confirmation")
|
||||
.clear()
|
||||
.type(BAD_PASSWORD_NO_NUMBER);
|
||||
cy.findByRole("button", { name: /submit/i }).click();
|
||||
cy.findByText(/password does not meet required criteria/i).should(
|
||||
"exist"
|
||||
);
|
||||
cy.getAttached("#password").clear().type(BAD_PASSWORD_NO_SYMBOL);
|
||||
cy.getAttached("#password_confirmation")
|
||||
.clear()
|
||||
.type(BAD_PASSWORD_NO_SYMBOL);
|
||||
cy.findByRole("button", { name: /submit/i }).click();
|
||||
cy.findByText(/password does not meet required criteria/i).should(
|
||||
"exist"
|
||||
);
|
||||
cy.getAttached("#password").clear().type(GOOD_PASSWORD);
|
||||
cy.getAttached("#password_confirmation").clear().type(GOOD_PASSWORD);
|
||||
cy.findByRole("button", { name: /submit/i }).click();
|
||||
|
||||
cy.getAttached(".login-form").within(() => {
|
||||
cy.findByLabelText(/email/i).clear().type("ash@example.com");
|
||||
cy.findByLabelText(/^password$/i)
|
||||
.click()
|
||||
.type(GOOD_PASSWORD);
|
||||
cy.findByRole("button", { name: /login/i }).click();
|
||||
});
|
||||
Cypress.session.clearAllSavedSessions(); // Switch back to admin user
|
||||
});
|
||||
it("shows new user in admin settings", () => {
|
||||
cy.getAttached("tbody>tr>td")
|
||||
.contains("Ash Ketchum")
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.findByText(/active/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
import dashboardPage from "../../pages/dashboardPage";
|
||||
|
||||
describe("Dashboard", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Operating systems card", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
|
||||
it("displays operating systems card if macOS platform is selected", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
});
|
||||
|
||||
it("displays operating systems card if Windows platform is selected", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
});
|
||||
|
||||
it("displays operating systems card if Linux platform is selected", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
});
|
||||
});
|
||||
describe("Hosts filter by dashboard host summary", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/dashboard");
|
||||
});
|
||||
it("filters macOS hosts", () => {
|
||||
cy.findByText(/macos hosts/i).click();
|
||||
cy.findByRole("status", {
|
||||
name: /hosts filtered by macos/i,
|
||||
}).should("exist");
|
||||
});
|
||||
it("filters Windows hosts", () => {
|
||||
cy.findByText(/windows hosts/i).click();
|
||||
cy.findByRole("status", {
|
||||
name: /hosts filtered by windows/i,
|
||||
}).should("exist");
|
||||
});
|
||||
|
||||
it("filters linux hosts", () => {
|
||||
cy.findByText(/macos hosts/i).click();
|
||||
cy.findByRole("status", {
|
||||
name: /hosts filtered by macos/i,
|
||||
}).should("exist");
|
||||
});
|
||||
// filters missing hosts and low disk space hosts on premium only, premium/admin.spec.ts
|
||||
});
|
||||
});
|
@ -1,88 +0,0 @@
|
||||
const fakeDeviceToken = "phAK3d3vIC37OK3n";
|
||||
|
||||
describe("Fleet Desktop", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.addDockerHost();
|
||||
cy.setDesktopToken(1, fakeDeviceToken);
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
describe("Fleet Desktop device user page", () => {
|
||||
beforeEach(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.visit(`/device/${fakeDeviceToken}`);
|
||||
});
|
||||
it("renders the device user information and info modal", () => {
|
||||
cy.findByText(/my device/i).should("exist");
|
||||
cy.getAttached(".status--online").should("exist");
|
||||
cy.getAttached(".info-flex").within(() => {
|
||||
cy.findByText(/ubuntu 20/i)
|
||||
.prev()
|
||||
.contains(/operating system/i);
|
||||
});
|
||||
cy.getAttached(".info-grid").within(() => {
|
||||
cy.findByText(/private ip address/i)
|
||||
.next()
|
||||
.findByText(/---/i)
|
||||
.should("not.exist");
|
||||
});
|
||||
cy.getAttached(".device-user__action-button-container").within(() => {
|
||||
cy.getAttached('img[alt="Host info icon"]').click();
|
||||
});
|
||||
cy.getAttached(".device-user-info__modal").within(() => {
|
||||
cy.findByRole("button", { name: /ok/i }).click();
|
||||
});
|
||||
});
|
||||
it("renders and searches the host's software", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/software/i).click();
|
||||
});
|
||||
let initialCount = 0;
|
||||
cy.getAttached(".section--software").within(() => {
|
||||
cy.getAttached(".table-container__results-count")
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
const fullText = text;
|
||||
const pattern = /[0-9]+/g;
|
||||
const newCount = fullText.match(pattern);
|
||||
initialCount = parseInt(newCount[0], 10);
|
||||
expect(initialCount).to.be.at.least(1);
|
||||
});
|
||||
cy.findByPlaceholderText(/search software/i).type("lib");
|
||||
// Ensures search completes
|
||||
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.getAttached(".table-container__results-count")
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
const fullText = text;
|
||||
const pattern = /[0-9]+/g;
|
||||
const newCount = fullText.match(pattern);
|
||||
const searchCount = parseInt(newCount[0], 10);
|
||||
expect(searchCount).to.be.lessThan(initialCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
it(
|
||||
"refetches host vitals",
|
||||
{
|
||||
retries: {
|
||||
runMode: 2,
|
||||
},
|
||||
defaultCommandTimeout: 15000,
|
||||
},
|
||||
() => {
|
||||
cy.getAttached(".display-name-container").within(() => {
|
||||
cy.contains("button", /refetch/i).click();
|
||||
cy.findByText(/fetching/i).should("exist");
|
||||
cy.contains("button", /refetch/i).should("exist");
|
||||
cy.findByText(/less than a minute/i).should("exist");
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -1,261 +0,0 @@
|
||||
import * as path from "path";
|
||||
import { format } from "date-fns";
|
||||
import manageHostsPage from "../../pages/manageHostsPage";
|
||||
import hostDetailsPage from "../../pages/hostDetailsPage";
|
||||
|
||||
let hostname = "";
|
||||
|
||||
describe("Hosts flow", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.addDockerHost();
|
||||
cy.clearDownloads();
|
||||
cy.seedQueries();
|
||||
cy.seedSchedule();
|
||||
cy.seedPolicies();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it("adds a new host and downloads installation files", () => {
|
||||
// Download add hosts files
|
||||
cy.getAttached(".manage-hosts").within(() => {
|
||||
cy.contains("button", /add hosts/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs").within(() => {
|
||||
cy.findByText(/advanced/i)
|
||||
.first()
|
||||
.should("exist")
|
||||
.click();
|
||||
});
|
||||
cy.getAttached(".reveal-button").click();
|
||||
cy.getAttached('a[href*="#downloadEnrollSecret"]').click();
|
||||
cy.getAttached('a[href*="#downloadCertificate"]').last().click();
|
||||
cy.getAttached('a[href*="#downloadFlagfile"]').click();
|
||||
|
||||
// NOTE: This test often fails when the Cypress downloads folder was not cleared properly
|
||||
// before each test run (seems to be related to issues with Cypress trashAssetsBeforeRun)
|
||||
if (Cypress.platform !== "win32") {
|
||||
// windows has issues with downloads location
|
||||
|
||||
// Feature pushed back from 4.13 release
|
||||
// const formattedTime = format(new Date(), "yyyy-MM-dd");
|
||||
// const filename = `Hosts ${formattedTime}.csv`;
|
||||
// cy.readFile(path.join(Cypress.config("downloadsFolder"), filename), {
|
||||
// timeout: 5000,
|
||||
// });
|
||||
cy.readFile(
|
||||
path.join(Cypress.config("downloadsFolder"), "secret.txt"),
|
||||
{
|
||||
timeout: 5000,
|
||||
}
|
||||
);
|
||||
cy.readFile(
|
||||
path.join(Cypress.config("downloadsFolder"), "flagfile.txt"),
|
||||
{
|
||||
timeout: 5000,
|
||||
}
|
||||
);
|
||||
cy.readFile(path.join(Cypress.config("downloadsFolder"), "fleet.pem"), {
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
});
|
||||
it(`exports hosts to CSV`, () => {
|
||||
cy.getAttached(".manage-hosts").within(() => {
|
||||
cy.getAttached(".manage-hosts__export-btn").click();
|
||||
});
|
||||
if (Cypress.platform !== "win32") {
|
||||
// windows has issues with downloads location
|
||||
const formattedTime = format(new Date(), "yyyy-MM-dd");
|
||||
const filename = `Hosts ${formattedTime}.csv`;
|
||||
cy.readFile(path.join(Cypress.config("downloadsFolder"), filename), {
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
});
|
||||
it(`hides and shows "Used by" column`, () => {
|
||||
cy.getAttached("thead").within(() =>
|
||||
cy.findByText(/used by/i).should("not.exist")
|
||||
);
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.contains("button", /edit columns/i).click();
|
||||
});
|
||||
cy.getAttached(".edit-columns-modal").within(() => {
|
||||
cy.findByLabelText(/used by/i).check({ force: true });
|
||||
cy.contains("button", /save/i).click();
|
||||
});
|
||||
cy.getAttached("thead").within(() =>
|
||||
cy.findByText(/used by/i).should("exist")
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it(
|
||||
"runs policy on an existing host",
|
||||
{
|
||||
retries: {
|
||||
runMode: 2,
|
||||
},
|
||||
defaultCommandTimeout: 10000,
|
||||
},
|
||||
() => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.get(".button--text-link").first().as("hostLink");
|
||||
});
|
||||
cy.getAttached("@hostLink")
|
||||
// Set hostname variable for later assertions
|
||||
.then((el) => {
|
||||
hostname = el.text();
|
||||
return el;
|
||||
})
|
||||
.click();
|
||||
// Go to host details page
|
||||
cy.location("pathname").should("match", /hosts\/[0-9]/i);
|
||||
cy.getAttached(".status--online").should("exist");
|
||||
// Run policy on host
|
||||
cy.contains("a", "Policies").click();
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.get(".button--text-link").first().as("policyLink");
|
||||
});
|
||||
cy.getAttached("@policyLink")
|
||||
// Set policyname variable for later assertions
|
||||
.then((el) => {
|
||||
console.log(el);
|
||||
return el;
|
||||
});
|
||||
cy.findByText(/filevault/i)
|
||||
.should("exist")
|
||||
.click();
|
||||
cy.getAttached(".policy-form__run").should("exist").click();
|
||||
cy.findByText(/all hosts/i)
|
||||
.should("exist")
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.findByText(/run/i).click();
|
||||
});
|
||||
cy.getAttached(".data-table").within(() => {
|
||||
cy.findByText(hostname).should("exist");
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".button--text-link").first().click();
|
||||
});
|
||||
});
|
||||
it("renders and searches the host's users", () => {
|
||||
cy.getAttached(".section--users").within(() => {
|
||||
cy.getAttached("tbody>tr").should("have.length.greaterThan", 0);
|
||||
cy.findByPlaceholderText(/search/i).type("Ash");
|
||||
cy.getAttached("tbody>tr").should("have.length", 0);
|
||||
cy.getAttached(".empty-table__container").within(() => {
|
||||
cy.findByText(/no users match/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
it("renders and searches the host's software", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/software/i).click();
|
||||
});
|
||||
let initialCount = 0;
|
||||
cy.getAttached(".section--software").within(() => {
|
||||
cy.getAttached(".table-container__results-count")
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
const fullText = text;
|
||||
const pattern = /[0-9]+/g;
|
||||
const newCount = fullText.match(pattern);
|
||||
initialCount = parseInt(newCount[0], 10);
|
||||
expect(initialCount).to.be.at.least(1);
|
||||
});
|
||||
cy.findByPlaceholderText(/search software/i).type("lib");
|
||||
// Ensures search completes
|
||||
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.getAttached(".table-container__results-count")
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
const fullText = text;
|
||||
const pattern = /[0-9]+/g;
|
||||
const newCount = fullText.match(pattern);
|
||||
const searchCount = parseInt(newCount[0], 10);
|
||||
expect(searchCount).to.be.lessThan(initialCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
it("host's software table links to filter hosts by software", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/software/i).click();
|
||||
});
|
||||
cy.getAttached(".software-link").first().click({ force: true });
|
||||
cy.findByText(/adduser 3.118ubuntu2/i).should("exist"); // first seeded software item
|
||||
cy.getAttached(".data-table").within(() => {
|
||||
cy.findByText(hostname).should("exist");
|
||||
});
|
||||
});
|
||||
it("host's software table links to software details", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/software/i).click();
|
||||
});
|
||||
cy.contains(/adduser/i).click();
|
||||
cy.findByText(/adduser, 3.118ubuntu2/i).should("exist");
|
||||
});
|
||||
it("renders host's schedule", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/schedule/i).click();
|
||||
});
|
||||
cy.getAttached(".data-table").within(() => {
|
||||
cy.getAttached(".query_name__header").should("exist");
|
||||
});
|
||||
});
|
||||
it("renders host's policies and links to filter hosts by policy status", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/policies/i).click();
|
||||
});
|
||||
cy.getAttached(".section--policies").within(() => {
|
||||
cy.findByText(/failing 1 policy/i).should("exist");
|
||||
cy.getAttached(".policy-link").first().click({ force: true });
|
||||
});
|
||||
cy.findAllByText(/Is Filevault enabled on macOS devices/i).should(
|
||||
"exist"
|
||||
);
|
||||
cy.getAttached(".data-table").within(() => {
|
||||
cy.findByText(hostname).should("exist");
|
||||
});
|
||||
});
|
||||
it(
|
||||
"refetches host vitals",
|
||||
{
|
||||
retries: {
|
||||
runMode: 2,
|
||||
},
|
||||
defaultCommandTimeout: 15000,
|
||||
},
|
||||
() => {
|
||||
cy.getAttached(".display-name-container").within(() => {
|
||||
cy.contains("button", /refetch/i).click();
|
||||
cy.findByText(/fetching/i).should("exist");
|
||||
cy.contains("button", /refetch/i).should("exist");
|
||||
cy.findByText(/less than a minute/i).should("exist");
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
@ -1,89 +0,0 @@
|
||||
import manageHostsPage from "../../pages/manageHostsPage";
|
||||
|
||||
describe("Labels flow", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.addDockerHost();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it("creates a custom label", () => {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.findByRole("button", { name: /add label/i }).click();
|
||||
cy.getAttached(".label-form__text-editor-wrapper .ace_content").type(
|
||||
"{selectall}{backspace}SELECT * FROM users;"
|
||||
);
|
||||
cy.findByLabelText(/name/i).click().type("Show all MAC users");
|
||||
cy.findByLabelText(/description/i)
|
||||
.click()
|
||||
.type("Select all MAC users.");
|
||||
cy.getAttached(".label-form__form-field--platform > .Select").click();
|
||||
cy.getAttached(".Select-menu-outer").within(() => {
|
||||
cy.findByText(/macOS/i).click();
|
||||
});
|
||||
cy.findByRole("button", { name: /save label/i }).click();
|
||||
cy.findByText(/label created/i).should("exist");
|
||||
});
|
||||
it("edits a custom label", () => {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.findByText(/Show all MAC users/i).click();
|
||||
cy.findByRole("button", { name: /edit label/i }).click();
|
||||
// SQL and Platform are immutable fields
|
||||
cy.findByLabelText(/name/i).clear().type("Show all mac usernames");
|
||||
cy.findByLabelText(/description/i)
|
||||
.clear()
|
||||
.type("Select all usernames on Mac.");
|
||||
cy.findByText(/select one/i).should("not.exist");
|
||||
cy.findByRole("button", { name: /update label/i }).click();
|
||||
cy.findByText(/label updated/i).should("exist");
|
||||
});
|
||||
it("deletes a custom label", () => {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.findByText(/Show all mac usernames/i).click();
|
||||
cy.findByRole("button", { name: /delete label/i }).click();
|
||||
cy.getAttached(".delete-label-modal")
|
||||
.contains("button", /delete/i)
|
||||
.click();
|
||||
cy.getAttached(".label-filter-select__control").within(() => {
|
||||
cy.findByText(/show all mac usernames/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
it("creates labels with special characters", () => {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.findByRole("button", { name: /add label/i }).click();
|
||||
cy.getAttached(".label-form__text-editor-wrapper .ace_content").type(
|
||||
"{selectall}{backspace}SELECT * FROM users;"
|
||||
);
|
||||
cy.findByLabelText(/name/i)
|
||||
.click()
|
||||
.type("** Special label (Mac / Users)");
|
||||
cy.findByLabelText(/description/i)
|
||||
.click()
|
||||
.type("Select all MAC users using special characters.");
|
||||
cy.getAttached(".label-form__form-field--platform > .Select").click();
|
||||
cy.getAttached(".Select-menu-outer").within(() => {
|
||||
cy.findByText(/macOS/i).click();
|
||||
});
|
||||
cy.findByRole("button", { name: /save label/i }).click();
|
||||
cy.findByText(/label created/i).should("exist");
|
||||
});
|
||||
it("searches labels with special characters", () => {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.findByPlaceholderText(/filter labels by name.../i).type(
|
||||
"{selectall}{backspace}**"
|
||||
);
|
||||
cy.findByText(/Special label/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,132 +0,0 @@
|
||||
import CONSTANTS from "../,,/../../../support/constants";
|
||||
|
||||
const {
|
||||
GOOD_PASSWORD,
|
||||
BAD_PASSWORD_LENGTH,
|
||||
BAD_PASSWORD_NO_NUMBER,
|
||||
BAD_PASSWORD_NO_SYMBOL,
|
||||
} = CONSTANTS;
|
||||
|
||||
describe("Manage users flow", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
cy.setupSMTP();
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
describe("User management page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/settings/users");
|
||||
});
|
||||
it("searches for an existing user", () => {
|
||||
cy.findByText("admin@example.com").should("exist");
|
||||
cy.findByText("maintainer@example.com").should("exist");
|
||||
cy.findByText("observer@example.com").should("exist");
|
||||
cy.findByText("sso_user@example.com").should("exist");
|
||||
|
||||
cy.findByPlaceholderText("Search").type("admin");
|
||||
|
||||
cy.getAttached("tbody>tr").should("have.length", 1);
|
||||
cy.findByText("admin@example.com").should("exist");
|
||||
cy.findByText("maintainer@example.com").should("not.exist");
|
||||
cy.findByText("observer@example.com").should("not.exist");
|
||||
cy.findByText("sso_user@example.com").should("not.exist");
|
||||
});
|
||||
it("creates a new user", () => {
|
||||
cy.contains("button:enabled", /create user/i).click();
|
||||
cy.findByPlaceholderText("Full name").type("New Name");
|
||||
cy.findByPlaceholderText("Email").type("new-user@example.com");
|
||||
cy.getAttached(
|
||||
".create-user-form__form-field--global-role > .Select"
|
||||
).click();
|
||||
cy.getAttached(".create-user-form__form-field--global-role").within(
|
||||
() => {
|
||||
cy.findByText(/maintainer/i).click();
|
||||
}
|
||||
);
|
||||
cy.findByPlaceholderText("Password").clear().type(BAD_PASSWORD_LENGTH);
|
||||
cy.getAttached(".modal-cta-wrap")
|
||||
.contains("button", /create/i)
|
||||
.click();
|
||||
cy.findByText(/password must meet the criteria below/i).should("exist");
|
||||
cy.findByLabelText(/password must meet the criteria below/i)
|
||||
.clear()
|
||||
.type(BAD_PASSWORD_NO_NUMBER);
|
||||
cy.getAttached(".modal-cta-wrap")
|
||||
.contains("button", /create/i)
|
||||
.click();
|
||||
cy.findByText(/password must meet the criteria below/i).should("exist");
|
||||
cy.findByLabelText(/password must meet the criteria below/i)
|
||||
.clear()
|
||||
.type(BAD_PASSWORD_NO_NUMBER);
|
||||
cy.getAttached(".modal-cta-wrap")
|
||||
.contains("button", /create/i)
|
||||
.click();
|
||||
cy.findByText(/password must meet the criteria below/i).should("exist");
|
||||
cy.findByLabelText(/password must meet the criteria below/i)
|
||||
.clear()
|
||||
.type(GOOD_PASSWORD);
|
||||
cy.getAttached(".modal-cta-wrap")
|
||||
.contains("button", /create/i)
|
||||
.click();
|
||||
cy.findByText(/new name/i).should("exist");
|
||||
});
|
||||
it("edits an existing user", () => {
|
||||
cy.getAttached("tbody>tr")
|
||||
.should("have.length", 5)
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/edit/i).click();
|
||||
});
|
||||
cy.findByPlaceholderText("Full name").clear().type("New Admin");
|
||||
cy.findByPlaceholderText("Email").clear().type("new-admin@example.com");
|
||||
cy.getAttached(
|
||||
".create-user-form__form-field--global-role > .Select"
|
||||
).click();
|
||||
cy.getAttached(".create-user-form__form-field--global-role").within(
|
||||
() => {
|
||||
cy.findByText(/admin/i).click();
|
||||
}
|
||||
);
|
||||
cy.findByLabelText("Password").clear().type(BAD_PASSWORD_LENGTH);
|
||||
cy.getAttached(".modal-cta-wrap").contains("button", /save/i).click();
|
||||
cy.findByText(/password must meet the criteria below/i).should("exist");
|
||||
cy.findByLabelText(/password must meet the criteria below/i)
|
||||
.clear()
|
||||
.type(BAD_PASSWORD_NO_NUMBER);
|
||||
cy.getAttached(".modal-cta-wrap").contains("button", /save/i).click();
|
||||
cy.findByText(/password must meet the criteria below/i).should("exist");
|
||||
cy.findByLabelText(/password must meet the criteria below/i)
|
||||
.clear()
|
||||
.type(BAD_PASSWORD_NO_SYMBOL);
|
||||
cy.getAttached(".modal-cta-wrap").contains("button", /save/i).click();
|
||||
cy.findByText(/password must meet the criteria below/i).should("exist");
|
||||
cy.findByLabelText(/password must meet the criteria below/i)
|
||||
.clear()
|
||||
.type(GOOD_PASSWORD);
|
||||
cy.getAttached(".modal-cta-wrap").contains("button", /save/i).click();
|
||||
cy.findByText(/successfully edited/i).should("exist");
|
||||
});
|
||||
it("deletes an existing user", () => {
|
||||
cy.getAttached("tbody>tr")
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.findByText(/new admin/i).should("exist");
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/delete/i).click();
|
||||
});
|
||||
cy.getAttached(".modal-cta-wrap")
|
||||
.contains("button", /delete/i)
|
||||
.click();
|
||||
cy.findByText(/successfully deleted/i).should("exist");
|
||||
cy.getAttached("tbody>tr").should("have.length", 4);
|
||||
cy.findByText(/new-user/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,92 +0,0 @@
|
||||
/* NOTE: Product decision to remove packs from UI
|
||||
|
||||
import managePacksPage from "../../pages/managePacksPage";
|
||||
|
||||
describe("Pack flow (empty)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Manage packs page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
});
|
||||
it("creates a new pack", () => {
|
||||
managePacksPage.allowsCreatePack();
|
||||
managePacksPage.verifiesCreatedPack();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Pack flow (seeded)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedQueries();
|
||||
cy.seedPacks();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Pack details page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
cy.getAttached(".name__cell > .button--text-link").first().click();
|
||||
});
|
||||
it("adds a query to an existing pack", () => {
|
||||
cy.findByRole("button", { name: /add query/i }).click();
|
||||
cy.findByText(/select query/i).click();
|
||||
cy.findByText(/get authorized/i).click();
|
||||
cy.getAttached(
|
||||
".pack-query-editor-modal__form-field--frequency > .input-field"
|
||||
)
|
||||
.click()
|
||||
.type("3600");
|
||||
cy.getAttached(
|
||||
".pack-query-editor-modal__form-field--osquer-vers > .Select"
|
||||
).click();
|
||||
cy.findByText(/4.7/i).click();
|
||||
cy.getAttached(
|
||||
".pack-query-editor-modal__form-field--shard > .input-field"
|
||||
)
|
||||
.click()
|
||||
.type("50");
|
||||
cy.getAttached(".pack-query-editor-modal .modal-cta-wrap")
|
||||
.contains("button", /add query/i)
|
||||
.click();
|
||||
cy.findByText(/get authorized/i).should("exist");
|
||||
});
|
||||
it("removes a query from an existing pack", () => {
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
cy.findByRole("button", { name: /remove/i }).click();
|
||||
cy.getAttached(".remove-pack-query-modal .modal-cta-wrap")
|
||||
.contains("button", /remove/i)
|
||||
.click();
|
||||
});
|
||||
it("edits an existing pack", () => {
|
||||
managePacksPage.allowsEditPack();
|
||||
managePacksPage.verifiesEditedPack();
|
||||
});
|
||||
});
|
||||
describe("Manage packs page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
});
|
||||
it("deletes an existing pack", () => {
|
||||
managePacksPage.allowsDeletePack();
|
||||
managePacksPage.verifiesDeletedPack();
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
@ -1,736 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
import managePoliciesPage from "../../pages/managePoliciesPage";
|
||||
|
||||
const {
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED,
|
||||
} = CONSTANTS;
|
||||
|
||||
const enableJiraPoliciesIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: true,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
enable_vulnerabilities_webhook: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const enableZendeskPoliciesIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: true,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
enable_vulnerabilities_webhook: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("Policies flow (empty)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
});
|
||||
it("creates a custom policy", () => {
|
||||
cy.getAttached(".empty-table__cta-buttons").within(() => {
|
||||
cy.findByText(/add a policy/i).click();
|
||||
});
|
||||
cy.findByText(/create your own policy/i).click();
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.click({ force: true })
|
||||
.type(
|
||||
"{selectall}SELECT 1 FROM users WHERE username = 'backup' LIMIT 1;"
|
||||
);
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.getAttached(".policy-form__policy-save-modal-name")
|
||||
.click()
|
||||
.type("Does the device have a user named 'backup'?");
|
||||
cy.getAttached(".policy-form__policy-save-modal-description")
|
||||
.click()
|
||||
.type("Returns yes or no for having a user named 'backup'");
|
||||
cy.getAttached(".policy-form__policy-save-modal-resolution")
|
||||
.click()
|
||||
.type("Create a user named 'backup'");
|
||||
cy.findByRole("button", { name: /save policy/i }).click();
|
||||
cy.findByText(/policy created/i).should("exist");
|
||||
});
|
||||
|
||||
it("creates a default policy", () => {
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Platform compatibility", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
});
|
||||
const platforms = ["macOS", "Windows", "Linux"];
|
||||
|
||||
const testCompatibility = (
|
||||
el: JQuery<HTMLElement>,
|
||||
i: number,
|
||||
expected: boolean[]
|
||||
) => {
|
||||
const check = expected[i]
|
||||
? "compatible-platform"
|
||||
: "incompatible-platform";
|
||||
const compatibility = expected[i] ? "compatible" : "incompatible";
|
||||
assert(
|
||||
el.children("div").attr("class").includes(check),
|
||||
`expected policy to be ${platforms[i]} ${compatibility}`
|
||||
);
|
||||
};
|
||||
|
||||
const testSelections = (
|
||||
el: JQuery<HTMLElement>,
|
||||
i: number,
|
||||
expected: boolean[]
|
||||
) => {
|
||||
assert(
|
||||
el.prop("checked") === expected[i],
|
||||
`expected ${platforms[i]} to be ${
|
||||
expected[i] ? "selected " : "not selected"
|
||||
}`
|
||||
);
|
||||
};
|
||||
|
||||
it("checks sql statement for platform compatibility", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByText(/add a policy/i).click();
|
||||
});
|
||||
cy.getAttached(".add-policy-modal").within(() => {
|
||||
cy.findByRole("button", { name: /create your own policy/i }).click();
|
||||
});
|
||||
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, true, true]);
|
||||
});
|
||||
|
||||
// Query with unknown table name displays error message
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall}SELECT 1 FROM foo WHERE start_time > 1;");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(700); // wait for text input debounce
|
||||
cy.getAttached(".platform-compatibility").within(() => {
|
||||
cy.findByText(
|
||||
"No platforms (check your query for invalid tables or tables that are supported on different platforms)"
|
||||
).should("exist");
|
||||
});
|
||||
|
||||
// Query with syntax error displays error message
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall}SELEC 1 FRO osquery_info WHER start_time > 1;");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(700); // wait for text input debounce
|
||||
cy.getAttached(".platform-compatibility").within(() => {
|
||||
cy.findByText(
|
||||
"No platforms (check your query for a possible syntax error)"
|
||||
).should("exist");
|
||||
});
|
||||
|
||||
// Query with no tables treated as compatible with all platforms
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall}SELECT * WHERE 1 = 1;");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(700); // wait for text input debounce
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, true, true]);
|
||||
});
|
||||
|
||||
// Tables defined in common table expression not factored into compatibility check
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall} ")
|
||||
.type(
|
||||
`WITH target_jars AS ( SELECT DISTINCT path FROM ( WITH split(word, str) AS( SELECT '', cmdline || ' ' FROM processes UNION ALL SELECT substr(str, 0, instr(str, ' ')), substr(str, instr(str, ' ') + 1) FROM split WHERE str != '') SELECT word AS path FROM split WHERE word LIKE '%.jar' UNION ALL SELECT path FROM process_open_files WHERE path LIKE '%.jar' ) ) SELECT path, matches FROM yara WHERE path IN (SELECT path FROM target_jars) AND count > 0 AND sigrule IN ( 'rule log4jJndiLookup { strings: $jndilookup = "JndiLookup" condition: $jndilookup }', 'rule log4jJavaClass { strings: $javaclass = "org/apache/logging/log4j" condition: $javaclass }' );`,
|
||||
{ parseSpecialCharSequences: false }
|
||||
);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000); // wait for text input debounce
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, false, true]);
|
||||
});
|
||||
|
||||
// Query with only macOS tables treated as compatible only with macOS
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.getAttached(" .policy-page__form .ace_scroller")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall} ")
|
||||
.wait(300) // wait for ace to clear text before proceeding
|
||||
.type(
|
||||
"{selectall}SELECT 1 FROM gatekeeper WHERE assessments_enabled = 1;"
|
||||
);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(700); // wait for text input debounce
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, false, false]);
|
||||
});
|
||||
|
||||
// Query with macadmins extension table is not treated as incompatible
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall}SELECT 1 FROM mdm WHERE enrolled='true';");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(700); // wait for text input debounce
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, false, false]);
|
||||
});
|
||||
});
|
||||
|
||||
it("preselects platforms to check based on platform compatiblity when saving new policy", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByText(/add a policy/i).click();
|
||||
});
|
||||
cy.getAttached(".add-policy-modal").within(() => {
|
||||
cy.findByText("Automatic login disabled (macOS)").click();
|
||||
});
|
||||
|
||||
cy.getAttached(".platform-compatibility").within(() => {
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, false, false]);
|
||||
});
|
||||
});
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.getAttached(".modal__content").within(() => {
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [true, false, false]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("disables modal save button if no platforms are selected", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByText(/add a policy/i).click();
|
||||
});
|
||||
cy.getAttached(".add-policy-modal").within(() => {
|
||||
cy.findByText("Automatic login disabled (macOS)").click();
|
||||
});
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
|
||||
cy.getAttached(".modal__content").within(() => {
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [true, false, false]);
|
||||
});
|
||||
cy.getAttached(".fleet-checkbox__label").first().click(); // deselect macOS
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [false, false, false]);
|
||||
});
|
||||
});
|
||||
|
||||
cy.getAttached(".modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /save policy/i }).should(
|
||||
"be.disabled"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("allows user to overide preselected platforms when saving new policy", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByText(/add a policy/i).click();
|
||||
});
|
||||
cy.getAttached(".add-policy-modal").within(() => {
|
||||
cy.findByText("Automatic login disabled (macOS)").click();
|
||||
});
|
||||
|
||||
cy.getAttached(".platform-compatibility").within(() => {
|
||||
cy.getAttached(".platform").each((el, i) => {
|
||||
testCompatibility(el, i, [true, false, false]);
|
||||
});
|
||||
});
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.getAttached(".modal__content").within(() => {
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [true, false, false]);
|
||||
});
|
||||
cy.getAttached(".fleet-checkbox__label").first().click(); // deselect macOS
|
||||
cy.getAttached(".fleet-checkbox__label").last().click(); // select Linux
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [false, false, true]);
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.findByRole("button", { name: /save policy/i }).click();
|
||||
cy.findByText(/policy created/i).should("exist");
|
||||
|
||||
// confirm that new policy was saved with user-selected platforms
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.contains("Automatic login disabled (macOS)")
|
||||
.click();
|
||||
});
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [false, false, true]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("allows user to edit existing policy platform selections", () => {
|
||||
// add a default policy for this test
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByText(/add a policy/i).click();
|
||||
});
|
||||
cy.getAttached(".add-policy-modal").within(() => {
|
||||
cy.findByText("Antivirus healthy (macOS)").click();
|
||||
});
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.findByRole("button", { name: /save policy/i }).click();
|
||||
cy.findByText(/policy created/i).should("exist");
|
||||
|
||||
// edit platform selections for policy
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.contains("Antivirus healthy (macOS)")
|
||||
.click();
|
||||
});
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [true, false, false]);
|
||||
});
|
||||
cy.getAttached(".fleet-checkbox__label").first().click(); // deselect macOS
|
||||
});
|
||||
|
||||
// confirm save/run buttons are disabled when no platforms are selected
|
||||
cy.findByRole("button", { name: /^Save$/ }).should("be.disabled");
|
||||
cy.findByRole("button", { name: /^Run$/ }).should("be.disabled");
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__label").last().click(); // select Linux
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [false, false, true]);
|
||||
});
|
||||
});
|
||||
|
||||
// save policy with new selection
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.findByText(/policy updated/i).should("exist");
|
||||
|
||||
// confirm that policy was saved with new selection
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.contains("Antivirus healthy (macOS)")
|
||||
.click();
|
||||
});
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [false, false, true]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Policies flow (seeded)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPolicies();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
});
|
||||
it("links to manage host page filtered by policy", () => {
|
||||
// Move internal clock forward 2 hours so that policies report host results
|
||||
cy.clock(Date.now() + 1000 * 60 * 120);
|
||||
cy.getAttached(".failing_host_count__cell")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getAttached(".button--text-link").click();
|
||||
});
|
||||
// confirm policy functionality on manage host page
|
||||
cy.getAttached(".manage-hosts__labels-active-filter-wrap").within(() => {
|
||||
cy.findByText(/filevault enabled/i).should("exist");
|
||||
cy.findByText(/no/i).should("exist").click();
|
||||
cy.findByText(/yes/i).should("exist");
|
||||
cy.get('img[alt="Remove filter"]').click();
|
||||
cy.findByText(/filevault enabled'/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
it("edits an existing policy", () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".name__cell .button--text-link").first().click();
|
||||
});
|
||||
cy.getAttached(".policy-page__form .ace_scroller")
|
||||
.click({ force: true })
|
||||
.type(
|
||||
"{selectall}SELECT 1 FROM gatekeeper WHERE assessments_enabled = 1;"
|
||||
);
|
||||
cy.getAttached(".fleet-checkbox__label").first().click();
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.findByText(/policy updated/i).should("exist");
|
||||
cy.visit("policies/1");
|
||||
cy.getAttached(".fleet-checkbox__input").first().should("not.be.checked");
|
||||
});
|
||||
|
||||
it("deletes an existing policy", () => {
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
managePoliciesPage.verifiesDeletedPolicy();
|
||||
});
|
||||
it("creates a failing policies webhook", () => {
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
// Ensure clicking on slider after modal animation
|
||||
cy.wait(300); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
});
|
||||
cy.getAttached("#webhook-url").click().type("http://www.foo.com/bar");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
// Ensure update
|
||||
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
// Confirm failing policies webhook was added successfully
|
||||
cy.findByText(/updated policy automations/i).should("exist");
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").should("be.checked");
|
||||
});
|
||||
// reset slider for subsequent tests
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
// Ensure clicking on slider after modal animation
|
||||
cy.wait(300); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
});
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
// Confirm failing policies webhook was updated successfully
|
||||
cy.findByText(/updated policy automations/i).should("exist");
|
||||
});
|
||||
it("empty automation state prompts to create an integration", () => {
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
});
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
|
||||
cy.findByText(/you have no integrations/i).should("exist");
|
||||
cy.getAttached(".manage-automations-modal__add-integration-link").click();
|
||||
// should be redirected to integrations settings page
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.findByText(/set up integration/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Manage policies page (mock integrations)", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1600, 900);
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS
|
||||
).as("getIntegrations");
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
});
|
||||
it("creates jira integration failing policies automation", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
cy.findByText(/project 1/i).click();
|
||||
cy.findByText(/project 2/i).click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
enableJiraPoliciesIntegration
|
||||
).as("enableJiraPoliciesIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableJiraPoliciesIntegration
|
||||
).as("enabledJiraPoliciesIntegration");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@enableJiraPoliciesIntegration").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm jira integration was added successfully
|
||||
cy.findByText(/updated policy automations/i).should("exist");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableJiraPoliciesIntegration
|
||||
).as("getIntegrations");
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
cy.findByText(/project 2/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("creates zendesk integration failing policies automation", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
cy.findByText(/project 1/i).click();
|
||||
cy.findByText(/87654321/i).click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
enableZendeskPoliciesIntegration
|
||||
).as("enableZendeskPoliciesIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableZendeskPoliciesIntegration
|
||||
).as("enabledZendeskPoliciesIntegration");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@enableZendeskPoliciesIntegration").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm zendesk integration was added successfully
|
||||
cy.findByText(/updated policy automations/i).should("exist");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableZendeskPoliciesIntegration
|
||||
).as("getIntegrations");
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
cy.findByText(/87654321/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("disables failing policies automation", () => {
|
||||
cy.getAttached(".manage-policies-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED
|
||||
).as("disablePoliciesAutomations");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED
|
||||
).as("disabledAutomations");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@disablePoliciesAutomations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@disabledAutomations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm integration was disabled successfully
|
||||
cy.findByText(/updated policy automations/i).should("exist");
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.findByText(/policy automations disabled/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Platform compatibility", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/policies/manage");
|
||||
});
|
||||
const platforms = ["macOS", "Windows", "Linux"];
|
||||
|
||||
const testSelections = (
|
||||
el: JQuery<HTMLElement>,
|
||||
i: number,
|
||||
expected: boolean[]
|
||||
) => {
|
||||
assert(
|
||||
el.prop("checked") === expected[i],
|
||||
`expected ${platforms[i]} to be ${
|
||||
expected[i] ? "selected " : "not selected"
|
||||
}`
|
||||
);
|
||||
};
|
||||
it('preselects all platforms if API response contains `platform: ""`', () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.contains("Is Ubuntu, version 16.4.0 or later, installed?")
|
||||
.click();
|
||||
});
|
||||
cy.getAttached(".platform-selector").within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").each((el, i) => {
|
||||
testSelections(el, i, [true, true, true]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,98 +0,0 @@
|
||||
import manageQueriesPage from "../../pages/manageQueriesPage";
|
||||
import manageSchedulePage from "../../pages/manageSchedulePage";
|
||||
|
||||
describe("Query flow (empty)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
describe("Manage queries page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageQueriesPage.visitManageQueriesPage();
|
||||
});
|
||||
it("creates a new query", () => {
|
||||
manageQueriesPage.allowsCreateNewQuery();
|
||||
manageQueriesPage.verifiesCreatedNewQuery();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Query flow (seeded)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedQueries();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
describe("Manage queries page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageQueriesPage.visitManageQueriesPage();
|
||||
});
|
||||
it("runs a live query and allows exporting results", () => {
|
||||
cy.addDockerHost();
|
||||
manageQueriesPage.allowsRunQuery();
|
||||
manageQueriesPage.verifiesRanQuery();
|
||||
manageQueriesPage.allowsViewRanQuery();
|
||||
manageQueriesPage.allowsExportQueryResults();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
it("edits an existing query", () => {
|
||||
manageQueriesPage.allowsEditExistingQuery();
|
||||
manageQueriesPage.verifiesEditedExistingQuery();
|
||||
});
|
||||
it("saves an existing query as new query", () => {
|
||||
manageQueriesPage.allowsSaveAsNewQuery();
|
||||
manageQueriesPage.verifiesSavedAsNewQuery();
|
||||
});
|
||||
it("deletes an existing query", () => {
|
||||
manageQueriesPage.allowsDeleteExistingQuery();
|
||||
manageQueriesPage.verifiesDeletedExistingQuery();
|
||||
});
|
||||
});
|
||||
describe("Manage schedules page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageSchedulePage.visitManageSchedulePage();
|
||||
});
|
||||
it("creates a new scheduled query", () => {
|
||||
manageSchedulePage.allowsAddSchedule();
|
||||
manageSchedulePage.verifiesAddedSchedule();
|
||||
});
|
||||
|
||||
it("shows sql of a scheduled query successfully", () => {
|
||||
cy.getAttached("tbody>tr")
|
||||
.should("have.length", 1)
|
||||
.within(() => {
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/show query/i).click();
|
||||
});
|
||||
cy.getAttached(".show-query-modal").within(() => {
|
||||
cy.getAttached(".ace_content").within(() => {
|
||||
cy.contains(/select/i).should("exist");
|
||||
cy.contains(/cypress/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("edit a scheduled query successfully", () => {
|
||||
manageSchedulePage.allowsEditSchedule();
|
||||
manageSchedulePage.verifiesEditedSchedule();
|
||||
});
|
||||
|
||||
it("remove a scheduled query successfully", () => {
|
||||
manageSchedulePage.allowsRemoveSchedule();
|
||||
manageSchedulePage.verifiesRemovedSchedule();
|
||||
});
|
||||
});
|
||||
});
|
@ -1,58 +0,0 @@
|
||||
describe("Reset sessions", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.setupSMTP();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("User settings page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
});
|
||||
it("resets a user's session generating a new api token", () => {
|
||||
cy.visit("/profile");
|
||||
cy.getAttached(".user-side-panel").within(() => {
|
||||
cy.findByRole("button", { name: /get api token/i }).click();
|
||||
});
|
||||
cy.getAttached(".secret-field__secret-input").within(() => {
|
||||
cy.getAttached(".secret-field__show-secret").click();
|
||||
cy.getAttached("input").invoke("val").as("token1");
|
||||
});
|
||||
cy.visit("/settings/users");
|
||||
cy.getAttached("div.Select-placeholder").eq(0).click();
|
||||
cy.contains(/reset sessions/i).click();
|
||||
|
||||
cy.get(".modal__modal_container").within(() => {
|
||||
cy.findByText(/reset sessions/i).should("exist");
|
||||
cy.findByRole("button", { name: /confirm/i }).click();
|
||||
});
|
||||
cy.findByText(/reset sessions/i).should("not.exist");
|
||||
// user should be logged out so log in for new API token
|
||||
cy.getAttached(".login-form__container").within(() => {
|
||||
cy.findByRole("button", { name: /login/i }).should("exist");
|
||||
});
|
||||
cy.login();
|
||||
cy.visit("/profile");
|
||||
cy.getAttached(".user-side-panel").within(() => {
|
||||
cy.findByRole("button", { name: /get api token/i }).click();
|
||||
});
|
||||
cy.getAttached(".modal__content").within(() => {
|
||||
cy.getAttached(".secret-field__show-secret").click();
|
||||
});
|
||||
cy.getAttached(".secret-field__secret-input").within(() => {
|
||||
cy.get("input").invoke("val").as("token2");
|
||||
});
|
||||
// new token should not equal old token
|
||||
cy.get("@token1").then((val1) => {
|
||||
cy.get("@token2").then((val2) => {
|
||||
expect(val1).to.not.eq(val2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,540 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
|
||||
const { CONFIG_INTEGRATIONS_AUTOMATIONS } = CONSTANTS;
|
||||
|
||||
const addJiraIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT",
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const deleteJiraIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const addZendeskIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const deleteZendeskIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
describe("App settings flow", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
describe("Organization settings page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/settings/organization");
|
||||
});
|
||||
it("edits organization info", () => {
|
||||
cy.getAttached(".app-config-form").within(() => {
|
||||
cy.findByLabelText(/organization name/i)
|
||||
.clear()
|
||||
.type("TJ's Run");
|
||||
cy.findByLabelText(/organization avatar url/i)
|
||||
.click()
|
||||
.type("http://tjsrun.com/img/logo.png");
|
||||
});
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
|
||||
cy.getAttached(".app-config-form").within(() => {
|
||||
cy.findByLabelText(/organization name/i).should(
|
||||
"have.value",
|
||||
"TJ's Run"
|
||||
);
|
||||
});
|
||||
|
||||
cy.findByLabelText(/organization avatar url/i).should(
|
||||
"have.value",
|
||||
"http://tjsrun.com/img/logo.png"
|
||||
);
|
||||
});
|
||||
|
||||
it("edits fleet web address", () => {
|
||||
cy.findByText(/fleet web address/i).click();
|
||||
|
||||
cy.findByLabelText(/fleet app url/i)
|
||||
.clear()
|
||||
.type("https://localhost:5000");
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/fleet web address/i).click();
|
||||
cy.findByLabelText(/fleet app url/i).should(
|
||||
"have.value",
|
||||
"https://localhost:5000"
|
||||
);
|
||||
});
|
||||
|
||||
it("edits single sign-on settings", () => {
|
||||
cy.findByText(/single sign-on options/i).click();
|
||||
cy.findByLabelText(/enable single sign-on/i).check({ force: true });
|
||||
|
||||
cy.findByLabelText(/identity provider name/i)
|
||||
.click({ force: true })
|
||||
.type("Rachel");
|
||||
|
||||
cy.findByLabelText(/entity id/i)
|
||||
.click({ force: true })
|
||||
.type("my entity id");
|
||||
|
||||
cy.findByLabelText(/idp image url/i)
|
||||
.click()
|
||||
.type("https://http.cat/100");
|
||||
|
||||
// specifically targeting this one to avoid conflict
|
||||
// with cypress seeing multiple "metadata url" - one
|
||||
// in a tooltip, the other as the actual label
|
||||
cy.getAttached("[for='metadataUrl']")
|
||||
.click()
|
||||
.type("http://github.com/fleetdm/fleet");
|
||||
|
||||
cy.findByLabelText(/allow sso login initiated/i).check({ force: true });
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/single sign-on options/i).click();
|
||||
cy.findByLabelText(/identity provider name/i).should(
|
||||
"have.value",
|
||||
"Rachel"
|
||||
);
|
||||
|
||||
cy.findByLabelText(/entity id/i).should("have.value", "my entity id");
|
||||
|
||||
cy.findByLabelText(/idp image url/i).should(
|
||||
"have.value",
|
||||
"https://http.cat/100"
|
||||
);
|
||||
|
||||
cy.getAttached("#metadataUrl").should(
|
||||
"have.value",
|
||||
"http://github.com/fleetdm/fleet"
|
||||
);
|
||||
});
|
||||
|
||||
it("edits smtp settings", () => {
|
||||
cy.findByText(/smtp options/i).click();
|
||||
cy.findByLabelText(/enable smtp/i).check({ force: true });
|
||||
|
||||
cy.findByLabelText(/sender address/i)
|
||||
.click({ force: true })
|
||||
.type("rachel@example.com");
|
||||
|
||||
// specifically targeting this one to avoid conflict
|
||||
// with cypress seeing multiple "metadata" - one
|
||||
// in a tooltip, the other as the actual label
|
||||
cy.findByLabelText(/SMTP server/)
|
||||
.click({ force: true })
|
||||
.type("localhost");
|
||||
|
||||
cy.getAttached("#smtpPort").clear().type("1025");
|
||||
|
||||
cy.findByLabelText(/use ssl\/tls/i).check({ force: true });
|
||||
|
||||
cy.findByLabelText(/smtp username/i)
|
||||
.click()
|
||||
.type("rachelsusername");
|
||||
|
||||
cy.findByLabelText(/smtp password/i)
|
||||
.click()
|
||||
.type("rachelspassword");
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/smtp options/i).click();
|
||||
cy.findByLabelText(/sender address/i).should(
|
||||
"have.value",
|
||||
"rachel@example.com"
|
||||
);
|
||||
|
||||
cy.getAttached("#smtpServer").should("have.value", "localhost");
|
||||
|
||||
cy.getAttached("#smtpPort").should("have.value", "1025");
|
||||
|
||||
cy.findByLabelText(/smtp username/i).should(
|
||||
"have.value",
|
||||
"rachelsusername"
|
||||
);
|
||||
cy.findByText(/single sign-on options/i).click();
|
||||
|
||||
cy.getAttached("#metadataUrl").should(
|
||||
"have.value",
|
||||
"http://github.com/fleetdm/fleet"
|
||||
);
|
||||
});
|
||||
|
||||
it("edits host status webhook", () => {
|
||||
cy.findByText(/host status webhook/i).click();
|
||||
cy.findByLabelText(/enable host status webhook/i).check({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.findByLabelText(/destination url/i)
|
||||
.click()
|
||||
.type("http://server.com/example");
|
||||
|
||||
cy.getAttached(
|
||||
".app-config-form__host-percentage .Select-control"
|
||||
).click();
|
||||
cy.getAttached(".Select-menu-outer").contains(/5%/i).click();
|
||||
|
||||
cy.getAttached(".app-config-form__days-count .Select-control").click();
|
||||
cy.getAttached(".Select-menu-outer")
|
||||
.contains(/7 days/i)
|
||||
.click();
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/host status webhook/i).click();
|
||||
|
||||
cy.findByLabelText(/destination url/i).should(
|
||||
"have.value",
|
||||
"http://server.com/example"
|
||||
);
|
||||
|
||||
cy.findByText(/5%/i).should("exist");
|
||||
|
||||
cy.findByText(/7 days/i).should("exist");
|
||||
cy.findByText(/1 day/i).should("not.exist");
|
||||
cy.findByText(/select one/i).should("not.exist");
|
||||
});
|
||||
|
||||
it("edits usage statistics", () => {
|
||||
cy.findByText(/usage statistics/i).click();
|
||||
cy.findByLabelText(/enable usage statistics/i).check({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/usage statistics/i).click();
|
||||
cy.findByLabelText(/enable usage statistics/i).should("be.checked");
|
||||
});
|
||||
|
||||
it("edits advanced options", () => {
|
||||
cy.findByText(/advanced options/i).click();
|
||||
|
||||
cy.findByLabelText(/domain/i)
|
||||
.click()
|
||||
.type("http://www.fleetdm.com");
|
||||
|
||||
cy.findByLabelText(/verify ssl certs/i).check({ force: true });
|
||||
cy.findByLabelText(/enable starttls/i).check({ force: true });
|
||||
cy.getAttached("[for='enableHostExpiry']").within(() => {
|
||||
cy.getAttached("[type='checkbox']").check({ force: true });
|
||||
});
|
||||
|
||||
// specifically targeting this one to avoid conflict
|
||||
// with cypress seeing multiple "host expiry" - one
|
||||
// in the checkbox above, the other as this label
|
||||
cy.getAttached("[name='hostExpiryWindow']").clear().type("5");
|
||||
|
||||
cy.findByLabelText(/disable live queries/i).check({ force: true });
|
||||
|
||||
cy.findByRole("button", { name: /save/i })
|
||||
.invoke("attr", "disabled", false)
|
||||
.click();
|
||||
|
||||
cy.findByText(/updated settings/i).should("exist");
|
||||
|
||||
// confirm edits
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/advanced options/i).click();
|
||||
|
||||
cy.findByLabelText(/verify ssl certs/i).should("be.checked");
|
||||
cy.findByLabelText(/enable starttls/i).should("be.checked");
|
||||
cy.findByLabelText(/host expiry window/i).should("have.value", "5");
|
||||
|
||||
// confirm smtp configured
|
||||
cy.getEmails().then((response) => {
|
||||
expect(response.body.items[0].To[0]).to.have.property("Domain");
|
||||
expect(response.body.items[0].To[0].Mailbox).to.equal("admin");
|
||||
expect(response.body.items[0].To[0].Domain).to.equal("example.com");
|
||||
expect(response.body.items[0].From.Mailbox).to.equal("rachel");
|
||||
expect(response.body.items[0].From.Domain).to.equal("example.com");
|
||||
expect(response.body.items[0].Content.Headers.Subject[0]).to.equal(
|
||||
"Hello from Fleet"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Integrations settings page (empty)", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/settings/integrations");
|
||||
});
|
||||
it("adds a new jira integration", () => {
|
||||
cy.getAttached(".no-integrations__add-button").click();
|
||||
cy.getAttached("#url").click().type("https://fleetdm.atlassian.com");
|
||||
cy.getAttached("#username").click().type("jira@example.com");
|
||||
cy.getAttached("#apiToken").click().type("jira123");
|
||||
cy.getAttached("#projectKey").click().type("PROJECT");
|
||||
cy.intercept("PATCH", "/api/latest/fleet/config", addJiraIntegration).as(
|
||||
"addIntegration"
|
||||
);
|
||||
cy.intercept("GET", "/api/latest/fleet/config", addJiraIntegration).as(
|
||||
"addedIntegration"
|
||||
);
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.wait("@addIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@addedIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.findByText(/successfully added/i).should("exist");
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.findByText(/fleetdm.atlassian.com - PROJECT/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("adds a new zendesk integration", () => {
|
||||
cy.getAttached(".no-integrations__add-button").click();
|
||||
cy.getAttached(".add-integration-modal__form-field--platform").within(
|
||||
() => {
|
||||
cy.findByText(/jira/i).click();
|
||||
cy.findByText(/zendesk/i).click();
|
||||
}
|
||||
);
|
||||
cy.getAttached("#url").click().type("https://fleetdm.zendesk.com");
|
||||
cy.getAttached("#email").click().type("zendesk1@example.com");
|
||||
cy.getAttached("#apiToken").click().type("zendesk123");
|
||||
cy.getAttached("#groupId").click().type("12345678");
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
addZendeskIntegration
|
||||
).as("addIntegration");
|
||||
cy.intercept("GET", "/api/latest/fleet/config", addZendeskIntegration).as(
|
||||
"addedIntegration"
|
||||
);
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.wait("@addIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@addedIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.findByText(/successfully added/i).should("exist");
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.findByText(/fleetdm.zendesk.com - 12345678/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Integrations settings page (seeded)", () => {
|
||||
beforeEach(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS
|
||||
).as("getIntegrations");
|
||||
cy.visit("/settings/integrations");
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
});
|
||||
it("deletes jira integration", () => {
|
||||
cy.getAttached("tbody>tr")
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.findByText(/project 2/i).should("exist");
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/delete/i).click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
deleteJiraIntegration
|
||||
).as("deleteIntegration");
|
||||
cy.intercept("GET", "/api/latest/fleet/config", deleteJiraIntegration).as(
|
||||
"deletedIntegration"
|
||||
);
|
||||
cy.getAttached(".delete-integration-modal .modal-cta-wrap")
|
||||
.contains("button", /delete/i)
|
||||
.click();
|
||||
cy.wait("@deleteIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@deletedIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.findByText(/successfully deleted/i).should("exist");
|
||||
cy.getAttached("tbody>tr").should("have.length", 3);
|
||||
cy.findByText(/project 2/i).should("not.exist");
|
||||
});
|
||||
it("deletes zendesk integration", () => {
|
||||
cy.getAttached("tbody>tr")
|
||||
.eq(3)
|
||||
.within(() => {
|
||||
cy.findByText(/87654321/i).should("exist");
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/delete/i).click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
deleteZendeskIntegration
|
||||
).as("deleteIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
deleteZendeskIntegration
|
||||
).as("deletedIntegration");
|
||||
cy.getAttached(".delete-integration-modal .modal-cta-wrap")
|
||||
.contains("button", /delete/i)
|
||||
.click();
|
||||
cy.wait("@deleteIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@deletedIntegration").then((configStub) => {
|
||||
cy.log(JSON.stringify(configStub));
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.findByText(/successfully deleted/i).should("exist");
|
||||
cy.getAttached("tbody>tr").should("have.length", 3);
|
||||
cy.findByText(/87654321/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,422 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
import manageSoftwarePage from "../../pages/manageSoftwarePage";
|
||||
|
||||
const {
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED,
|
||||
} = CONSTANTS;
|
||||
|
||||
const enableWebhook = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
destination_url: "http://www.foo.com/bar",
|
||||
enable_vulnerabilities_webhook: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const enableJiraSoftwareIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: true,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
destination_url: "http://www.foo.com/bar",
|
||||
enable_vulnerabilities_webhook: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const enableZendeskSoftwareIntegration = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
destination_url: "http://www.foo.com/bar",
|
||||
enable_vulnerabilities_webhook: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("Software", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setupWithSoftware();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1600, 900);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
// describe("Manage software page", () => {
|
||||
// beforeEach(() => {
|
||||
// cy.loginWithCySession();
|
||||
// cy.viewport(1600, 900);
|
||||
// manageSoftwarePage.visitManageSoftwarePage();
|
||||
// });
|
||||
// it("renders and searches the host's software, links to filter hosts by software", () => {
|
||||
// // cy.getAttached(".manage-software-page__count").within(() => {
|
||||
// // cy.findByText(/902 software items/i).should("exist");
|
||||
// // });
|
||||
// cy.findByPlaceholderText(/search software/i).type("lib");
|
||||
// // Ensures search completes
|
||||
// cy.wait(3000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
// cy.getAttached(".table-container__results-count")
|
||||
// .invoke("text")
|
||||
// .then((text) => {
|
||||
// const fullText = text;
|
||||
// const pattern = /[0-9]+/g;
|
||||
// const newCount = fullText.match(pattern);
|
||||
// const searchCount = parseInt(newCount[0], 10);
|
||||
// expect(searchCount).to.be.equal(444);
|
||||
// });
|
||||
// cy.getAttached(".software-link").first().click({ force: true });
|
||||
// cy.getAttached(".manage-hosts__software-filter-block").within(() => {
|
||||
// cy.getAttached(".manage-hosts__software-filter-name-card").should(
|
||||
// "exist"
|
||||
// );
|
||||
// });
|
||||
// cy.getAttached(".table-container__results-count")
|
||||
// .invoke("text")
|
||||
// .then((text) => {
|
||||
// const fullText = text;
|
||||
// const pattern = /[0-9]+/g;
|
||||
// const newCount = fullText.match(pattern);
|
||||
// const searchCount = parseInt(newCount[0], 10);
|
||||
// expect(searchCount).to.be.equal(2);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
describe("Manage software page (mock integrations)", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1600, 900);
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS
|
||||
).as("getIntegrations");
|
||||
manageSoftwarePage.visitManageSoftwarePage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
});
|
||||
it("creates webhook software vulnerability automation", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached("#webhook-radio-btn").next().click();
|
||||
});
|
||||
cy.getAttached("#webhook-url").click().type("http://www.foo.com/bar");
|
||||
cy.intercept("PATCH", "/api/latest/fleet/config", enableWebhook).as(
|
||||
"createWebhook"
|
||||
);
|
||||
cy.intercept("GET", "/api/latest/fleet/config", enableWebhook).as(
|
||||
"createdWebhook"
|
||||
);
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@createWebhook").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@createdWebhook").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm manage automations webhook was added successfully
|
||||
cy.findByText(/updated vulnerability automations/i).should("exist");
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
cy.getAttached("#webhook-url").should("exist");
|
||||
});
|
||||
});
|
||||
it("creates jira integration software vulnerability automation", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
cy.findByText(/project 1/i).click();
|
||||
cy.findByText(/project 2/i).click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
enableJiraSoftwareIntegration
|
||||
).as("enableJiraSoftwareIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableJiraSoftwareIntegration
|
||||
).as("enabledJiraSoftwareIntegration");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@enableJiraSoftwareIntegration").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm jira integration was added successfully
|
||||
cy.findByText(/updated vulnerability automations/i).should("exist");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableJiraSoftwareIntegration
|
||||
).as("getIntegrations");
|
||||
manageSoftwarePage.visitManageSoftwarePage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
cy.findByText(/project 2/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("creates zendesk integration software vulnerability automation", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
cy.findByText(/project 1/i).click();
|
||||
cy.findByText(/87654321/i).click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
enableZendeskSoftwareIntegration
|
||||
).as("enableZendeskSoftwareIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableZendeskSoftwareIntegration
|
||||
).as("enabledZendeskIntegration");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@enableZendeskSoftwareIntegration").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm zendesk integration was added successfully
|
||||
cy.findByText(/updated vulnerability automations/i).should("exist");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
enableZendeskSoftwareIntegration
|
||||
).as("getIntegrations");
|
||||
manageSoftwarePage.visitManageSoftwarePage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
cy.findByText(/87654321/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("disables software vulnerability automation", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
});
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED
|
||||
).as("disableSoftwareAutomations");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED
|
||||
).as("disabledAutomations");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
cy.wait("@disableSoftwareAutomations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
cy.wait("@disabledAutomations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
// Confirm integration was disabled successfully
|
||||
cy.findByText(/updated vulnerability automations/i).should("exist");
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.findByText(/vulnerability automations disabled/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,38 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
import manageHostsPage from "../../pages/manageHostsPage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe("Sessions", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
});
|
||||
it("logs in and out successfully", () => {
|
||||
cy.visit("/");
|
||||
cy.getAttached(".login-form__forgot-link").should("exist");
|
||||
// Log in
|
||||
cy.getAttached("input").first().type("admin@example.com");
|
||||
cy.getAttached("input").last().type(GOOD_PASSWORD);
|
||||
cy.getAttached("button").click();
|
||||
// Verify dashboard
|
||||
cy.url().should("include", "/dashboard");
|
||||
cy.contains("Host");
|
||||
// Log out
|
||||
cy.getAttached(".user-menu button").first().click();
|
||||
cy.contains("button", "Sign out").click();
|
||||
cy.url().should("match", /\/login$/);
|
||||
});
|
||||
it("fails login with invalid password", () => {
|
||||
cy.visit("/");
|
||||
cy.getAttached("input").first().type("admin@example.com");
|
||||
cy.getAttached("input").last().type("bad_password");
|
||||
cy.getAttached(".button").click();
|
||||
cy.url().should("match", /\/login$/);
|
||||
cy.contains("Authentication failed");
|
||||
});
|
||||
it("fails to access authenticated resource", () => {
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
cy.url().should("match", /\/login$/);
|
||||
});
|
||||
});
|
@ -1,64 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
const enable_sso_idp_login = true;
|
||||
|
||||
describe("SSO Sessions", () => {
|
||||
beforeEach(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
});
|
||||
it("non-SSO user can login with username/password", () => {
|
||||
cy.login();
|
||||
cy.setupSSO({ enable_sso_idp_login });
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
cy.getAttached(".login-form__forgot-link").should("exist");
|
||||
// Log in
|
||||
cy.getAttached("input").first().type("admin@example.com");
|
||||
cy.getAttached("input").last().type(GOOD_PASSWORD);
|
||||
cy.contains("button", "Login").click();
|
||||
// Verify dashboard
|
||||
cy.url().should("include", "/dashboard");
|
||||
cy.contains("Hosts");
|
||||
// Log out
|
||||
cy.getAttached(".user-menu button").first().click();
|
||||
cy.contains("button", "Sign out").click();
|
||||
cy.url().should("match", /\/login$/);
|
||||
});
|
||||
it("can login via SSO", () => {
|
||||
cy.login();
|
||||
cy.setupSSO({ enable_sso_idp_login });
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
// Log in
|
||||
cy.contains("button", "Sign on with SimpleSAML");
|
||||
cy.loginSSO();
|
||||
cy.contains("Hosts");
|
||||
});
|
||||
it("can't login if doesn't have an account", () => {
|
||||
cy.login();
|
||||
cy.setupSSO({ enable_sso_idp_login });
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
// Log in
|
||||
cy.contains("button", "Sign on with SimpleSAML");
|
||||
cy.loginSSO({ username: "sso_user2" });
|
||||
cy.visit("/login?status=account_invalid");
|
||||
});
|
||||
it("fails when IdP login disabled", () => {
|
||||
cy.login();
|
||||
cy.setupSSO();
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
cy.contains("button", "Sign on with SimpleSAML");
|
||||
cy.loginSSO();
|
||||
// Log in should fail
|
||||
cy.contains("Password");
|
||||
});
|
||||
it("displays an error message when status is set", () => {
|
||||
cy.visit("/login?status=account_disabled");
|
||||
cy.getAttached(".flash-message");
|
||||
});
|
||||
});
|
@ -1,64 +0,0 @@
|
||||
import CONSTANTS from "../../../support/constants";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
const fillOutForm = () => {
|
||||
// Page 1
|
||||
cy.findByLabelText(/full name/i).type("Test name");
|
||||
|
||||
cy.findByLabelText(/email/i).type("test@example.com");
|
||||
|
||||
cy.findByLabelText(/^password/i)
|
||||
.first()
|
||||
.type(GOOD_PASSWORD);
|
||||
|
||||
cy.findByLabelText(/confirm password/i)
|
||||
.last()
|
||||
.type(GOOD_PASSWORD);
|
||||
|
||||
cy.contains("button:enabled", /next/i).click();
|
||||
|
||||
// Page 2
|
||||
cy.findByLabelText(/organization name/i).type("Fleet Test");
|
||||
|
||||
cy.contains("button:enabled", /next/i).click();
|
||||
|
||||
// Page 3
|
||||
cy.contains("button:enabled", /next/i).click();
|
||||
|
||||
// Page 4
|
||||
cy.contains("button:enabled", /confirm/i).click();
|
||||
};
|
||||
|
||||
describe("Setup", () => {
|
||||
// Different than normal beforeEach because we don't run the fleetctl setup.
|
||||
beforeEach(() => {
|
||||
const SHELL = Cypress.platform === "win32" ? "cmd" : "bash";
|
||||
cy.exec("make e2e-reset-db", {
|
||||
timeout: 20000,
|
||||
env: { SHELL },
|
||||
});
|
||||
});
|
||||
|
||||
it("Completes setup", () => {
|
||||
cy.visit("/");
|
||||
cy.url().should("match", /\/setup$/);
|
||||
cy.contains(/setup/i);
|
||||
|
||||
fillOutForm();
|
||||
|
||||
cy.url().should("match", /\/hosts\/manage$/i);
|
||||
cy.contains(/add your devices/i);
|
||||
});
|
||||
|
||||
it("shows messaging when there is an error during setup", () => {
|
||||
cy.visit("/");
|
||||
cy.intercept("POST", "/api/v1/setup", { forceNetworkError: true });
|
||||
|
||||
fillOutForm();
|
||||
|
||||
cy.findByText(
|
||||
"We were unable to configure Fleet. If your Fleet server is behind a proxy, please ensure the server can be reached."
|
||||
).should("exist");
|
||||
});
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
# Free tier tests
|
||||
|
||||
These tests should only run when the server is in `free` tier.
|
||||
|
||||
To enable the tests:
|
||||
|
||||
```sh
|
||||
export CYPRESS_FLEET_TIER=free
|
||||
```
|
||||
|
||||
Before running the appropriate `yarn cypress (open|run)` command.
|
||||
|
||||
## Filtering
|
||||
|
||||
Any test suite in this directory should use the following pattern for filtering:
|
||||
|
||||
**FIXME**: There must be a better way to do this for all tests in the directory rather than having to add the check in each file?
|
||||
|
||||
```js
|
||||
if (Cypress.env("FLEET_TIER") === "free") {
|
||||
// test suite here
|
||||
}
|
||||
```
|
@ -1,226 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe(
|
||||
"Free tier - Admin user",
|
||||
{
|
||||
defaultCommandTimeout: 20000,
|
||||
},
|
||||
() => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.setupSMTP();
|
||||
cy.seedFree();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies();
|
||||
cy.addDockerHost();
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
it("displays intended admin top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs__tab--selected").within(() => {
|
||||
cy.findByText(/organization/i).should("exist");
|
||||
});
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/manage users/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs__tab--selected").within(() => {
|
||||
cy.findByText(/users/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
it("displays cards for all platforms and does not filter host platform", () => {
|
||||
dashboardPage.displaysCards("All");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("none");
|
||||
});
|
||||
it("displays cards for windows only and filters hosts by Windows platform", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Windows");
|
||||
});
|
||||
it("displays cards for linux only and filters hosts by Linux platform", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Linux");
|
||||
});
|
||||
it("displays cards for macOS only and filters hosts by macOS platform", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("macOS");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it("verifies teams is disabled on Manage hosts page", () => {
|
||||
manageHostsPage.verifiesTeamsIsDisabled();
|
||||
});
|
||||
it("allows admin to see and click CTA buttons", () => {
|
||||
manageHostsPage.allowsAddLabelForm();
|
||||
manageHostsPage.allowsAddHosts();
|
||||
manageHostsPage.allowsManageAndAddSecrets();
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
hostDetailsPage.visitsHostDetailsPage(1);
|
||||
});
|
||||
it("verifies teams is disabled on Host Details page", () => {
|
||||
hostDetailsPage.verifiesTeamsisDisabled();
|
||||
hostDetailsPage.hidesButton("Transfer");
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
manageSoftwarePage.visitManageSoftwarePage();
|
||||
});
|
||||
it("allows admin to click 'Manage automations' button", () => {
|
||||
manageSoftwarePage.allowsManageAutomations();
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
manageQueriesPage.visitManageQueriesPage();
|
||||
});
|
||||
it("allows admin add a new query", () => {
|
||||
manageQueriesPage.allowsCreateNewQuery();
|
||||
manageQueriesPage.verifiesCreatedNewQuery();
|
||||
});
|
||||
it("allows admin to edit a query", () => {
|
||||
manageQueriesPage.allowsEditExistingQuery();
|
||||
manageQueriesPage.verifiesEditedExistingQuery();
|
||||
});
|
||||
it("allows admin to run a query", () => {
|
||||
manageQueriesPage.allowsRunQuery();
|
||||
manageQueriesPage.verifiesRanQuery();
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
});
|
||||
it("allows admin to click 'Manage automations' button", () => {
|
||||
managePoliciesPage.allowsAutomatePolicy();
|
||||
managePoliciesPage.verifiesAutomatedPolicy();
|
||||
});
|
||||
it("allows admin to add a new policy", () => {
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
it("allows admin to delete a policy", () => {
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
});
|
||||
it("allows admin to select a policy and see CTAs to run and save", () => {
|
||||
managePoliciesPage.allowsSelectRunSavePolicy();
|
||||
});
|
||||
});
|
||||
describe("Admin settings page", () => {
|
||||
// cypress tends to fail on uncaught exceptions. since we have
|
||||
// our own error handling, it's suggested to use this block to
|
||||
// suppress so the tests will keep running
|
||||
Cypress.on("uncaught:exception", () => {
|
||||
return false;
|
||||
});
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
cy.visit("/settings/users");
|
||||
});
|
||||
it("hides access to Fleet Desktop settings", () => {
|
||||
cy.visit("settings/organization");
|
||||
cy.findByRole("navigation", { name: "settings" }).within(() => {
|
||||
cy.findByText(/organization info/i).should("exist");
|
||||
cy.findByText(/fleet desktop/i).should("not.exist");
|
||||
});
|
||||
cy.visit("settings/organization/fleet-desktop");
|
||||
cy.findAllByText(/access denied/i).should("exist");
|
||||
});
|
||||
it("hides access team settings", () => {
|
||||
cy.findByText(/teams/i).should("not.exist");
|
||||
});
|
||||
it("allows admin to access integrations and users settings", () => {
|
||||
cy.getAttached(".react-tabs").within(() => {
|
||||
cy.findByText(/organization settings/i).should("exist");
|
||||
cy.findByText(/integrations/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs").within(() => {
|
||||
cy.findByText(/users/i).click();
|
||||
});
|
||||
});
|
||||
it("displays the 'Create user' button", () => {
|
||||
cy.findByRole("button", { name: /create user/i }).click({
|
||||
force: true,
|
||||
});
|
||||
});
|
||||
it("hides assigning a user to a team", () => {
|
||||
cy.findByText(/team/i).should("not.exist");
|
||||
});
|
||||
it("allows admin to edit existing user password", () => {
|
||||
cy.visit("/settings/users");
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.findByText(/mary@organization.com/i)
|
||||
.parent()
|
||||
.next()
|
||||
.within(() => cy.getAttached(".Select-placeholder").click());
|
||||
});
|
||||
cy.getAttached(".Select-menu").within(() => {
|
||||
cy.findByText(/edit/i).click();
|
||||
});
|
||||
cy.getAttached(".create-user-form").within(() => {
|
||||
cy.findByLabelText(/email/i).should("exist");
|
||||
cy.findByLabelText(/password/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("verifies admin is not authorized to reach the Team Settings page", () => {
|
||||
cy.visit("/settings/teams");
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
userProfilePage.visitUserProfilePage();
|
||||
});
|
||||
it("verifies admin role and team", () => {
|
||||
userProfilePage.showRole("Admin");
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -1,191 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import managePacksPage from "../pages/managePacksPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe(
|
||||
"Free tier - Maintainer user",
|
||||
{
|
||||
defaultCommandTimeout: 20000,
|
||||
},
|
||||
() => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.setupSMTP();
|
||||
cy.seedFree();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies();
|
||||
cy.addDockerHost();
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
it("displays intended global maintainer top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/manage users/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
it("displays cards for all platforms and does not filter host platform", () => {
|
||||
dashboardPage.displaysCards("All");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("none");
|
||||
});
|
||||
it("displays cards for windows only and filters hosts by Windows platform", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Windows");
|
||||
});
|
||||
it("displays cards for linux only and filters hosts by Linux platform", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Linux");
|
||||
});
|
||||
it("displays cards for macOS only and filters hosts by macOS platform", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("macOS");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it("verifies teams is disabled", () => {
|
||||
manageHostsPage.verifiesTeamsIsDisabled();
|
||||
});
|
||||
it("allows maintainer to see and click 'Add label', 'Add hosts', and 'Manage enroll secrets' buttons", () => {
|
||||
manageHostsPage.allowsAddHosts();
|
||||
manageHostsPage.allowsManageAndAddSecrets();
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
hostDetailsPage.visitsHostDetailsPage(1);
|
||||
});
|
||||
it("verifies teams is disabled", () => {
|
||||
hostDetailsPage.verifiesTeamsisDisabled();
|
||||
hostDetailsPage.hidesButton("Transfer");
|
||||
});
|
||||
it("allows maintainer to create an operating system policy", () => {
|
||||
hostDetailsPage.allowsCreateOsPolicy();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => manageSoftwarePage.visitManageSoftwarePage());
|
||||
it("hides 'Manage automations' button from global maintainer", () => {
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
manageQueriesPage.visitManageQueriesPage();
|
||||
});
|
||||
it("allows maintainer to add a new query", () => {
|
||||
manageQueriesPage.allowsCreateNewQuery();
|
||||
manageQueriesPage.verifiesCreatedNewQuery();
|
||||
});
|
||||
it("allows maintainer to edit a query", () => {
|
||||
manageQueriesPage.allowsEditExistingQuery();
|
||||
manageQueriesPage.verifiesEditedExistingQuery();
|
||||
});
|
||||
it("allows maintainer to run a query", () => {
|
||||
manageQueriesPage.allowsRunQuery();
|
||||
manageQueriesPage.verifiesRanQuery();
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
});
|
||||
it("hides manage automations from maintainer", () => {
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
});
|
||||
it("allows maintainer to add a policy", () => {
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
it("allows maintainer to delete a policy", () => {
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
});
|
||||
it("allows maintainer to select a policy and see CTAs to run and save", () => {
|
||||
managePoliciesPage.allowsRunSavePolicy();
|
||||
});
|
||||
});
|
||||
/* NOTE: Product decision to remove packs from UI
|
||||
describe("Manage packs page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
});
|
||||
it("allows maintainer to create a pack", () => {
|
||||
managePacksPage.allowsCreatePack();
|
||||
managePacksPage.verifiesCreatedPack();
|
||||
});
|
||||
it("allows maintainer to delete a pack", () => {
|
||||
managePacksPage.allowsDeletePack();
|
||||
managePacksPage.verifiesDeletedPack();
|
||||
});
|
||||
});
|
||||
*/
|
||||
describe("User profile page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
userProfilePage.visitUserProfilePage();
|
||||
});
|
||||
it("verifies maintainer role and teams is disabled", () => {
|
||||
userProfilePage.showRole("Maintainer");
|
||||
});
|
||||
});
|
||||
|
||||
// nav restrictions are at the end because we expect to see a
|
||||
// 403 error overlay which will hide the nav and make the test fail
|
||||
describe("Nav restrictions", () => {
|
||||
// cypress tends to fail on uncaught exceptions. since we have
|
||||
// our own error handling, it's suggested to use this block to
|
||||
// suppress so the tests will keep running
|
||||
Cypress.on("uncaught:exception", () => {
|
||||
return false;
|
||||
});
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
it("verifies maintainer does not have access to settings", () => {
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -1,180 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import managePacksPage from "../pages/managePacksPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import manageSchedulePage from "../pages/manageSchedulePage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe("Free tier - Observer user", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.setupSMTP();
|
||||
cy.seedFree();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies();
|
||||
cy.addDockerHost();
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
it("displays intended global observer top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("not.exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/manage users/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
dashboardPage.visitsDashboardPage();
|
||||
});
|
||||
it("displays cards for all platforms and does not filter host platform", () => {
|
||||
dashboardPage.displaysCards("All");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("none");
|
||||
});
|
||||
it("displays cards for windows only and filters hosts by Windows platform", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Windows");
|
||||
});
|
||||
it("displays cards for linux only and filters hosts by Linux platform", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Linux");
|
||||
});
|
||||
it("displays cards for macOS only and filters hosts by macOS platform", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("macOS");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it("verifies teams is disabled", () => {
|
||||
manageHostsPage.verifiesTeamsIsDisabled();
|
||||
});
|
||||
it("hides 'Add hosts', 'Add label', and 'Manage enroll secrets' buttons", () => {
|
||||
manageHostsPage.hidesButton("Add label");
|
||||
manageHostsPage.hidesButton("Add hosts");
|
||||
manageHostsPage.hidesButton("Manage enroll secret");
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
hostDetailsPage.visitsHostDetailsPage(1);
|
||||
});
|
||||
it("verifies teams is disabled on Host Details page", () => {
|
||||
hostDetailsPage.verifiesTeamsisDisabled();
|
||||
});
|
||||
it("hides all cta buttons", () => {
|
||||
hostDetailsPage.hidesButton("Transfer");
|
||||
hostDetailsPage.hidesButton("Query");
|
||||
hostDetailsPage.hidesButton("Delete");
|
||||
hostDetailsPage.hidesCreateOSPolicy();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
manageSoftwarePage.visitManageSoftwarePage();
|
||||
});
|
||||
it("hides manage automations button", () => {
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
describe("Query page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
manageQueriesPage.visitManageQueriesPage();
|
||||
});
|
||||
it("hides 'Create a query' button", () => {
|
||||
manageQueriesPage.hidesButton("Create new query");
|
||||
});
|
||||
it("verifies observer can select a query and only run it", () => {
|
||||
cy.getAttached(".data-table__table").within(() => {
|
||||
cy.findByRole("button", { name: /detect presence/i }).click();
|
||||
});
|
||||
cy.findByText(/packs/i).should("not.exist");
|
||||
cy.findByLabelText(/query name/i).should("not.exist");
|
||||
cy.findByLabelText(/sql/i).should("not.exist");
|
||||
cy.findByLabelText(/description/i).should("not.exist");
|
||||
cy.findByLabelText(/observer can run/i).should("not.exist");
|
||||
cy.findByText(/show sql/i).click();
|
||||
cy.findByRole("button", { name: /run query/i }).should("exist");
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
});
|
||||
it("hides manage automations button", () => {
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
});
|
||||
it("hides 'Add a policy' button", () => {
|
||||
managePoliciesPage.hidesButton("Add a policy");
|
||||
});
|
||||
it("hides 'Run', 'Edit', and 'Delete' a policy", () => {
|
||||
managePoliciesPage.allowsViewPolicyOnly();
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
userProfilePage.visitUserProfilePage();
|
||||
});
|
||||
it("verifies user role and teams is disabled", () => {
|
||||
userProfilePage.showRole("Observer");
|
||||
});
|
||||
});
|
||||
|
||||
// nav restrictions are at the end because we expect to see a
|
||||
// 403 error overlay which will hide the nav and make the test fail
|
||||
describe("Nav restrictions", () => {
|
||||
// cypress tends to fail on uncaught exceptions. since we have
|
||||
// our own error handling, it's suggested to use this block to
|
||||
// suppress so the tests will keep running
|
||||
Cypress.on("uncaught:exception", () => {
|
||||
return false;
|
||||
});
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
it("should restrict navigation according to role-based access controls", () => {
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/schedule/i).should("not.exist");
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
manageSchedulePage.visitManageSchedulePage();
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,116 +0,0 @@
|
||||
const dashboardPage = {
|
||||
visitsDashboardPage: () => {
|
||||
cy.visit("/dashboard");
|
||||
},
|
||||
|
||||
switchesPlatform: (platform = "") => {
|
||||
cy.getAttached(".dashboard-page__platform_dropdown").click();
|
||||
cy.getAttached(".Select-menu-outer").within(() => {
|
||||
cy.findAllByText(platform).click();
|
||||
});
|
||||
},
|
||||
|
||||
displaysCards: (platform = "", tier = "free") => {
|
||||
switch (platform) {
|
||||
case "macOS":
|
||||
cy.getAttached(".dashboard-page__wrapper").within(() => {
|
||||
cy.findByText(/platform/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".operating-systems").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
cy.get(".activity-feed").should("not.exist");
|
||||
if (tier === "premium") {
|
||||
cy.getAttached(".hosts-missing").should("exist");
|
||||
cy.getAttached(".hosts-low-space").should("exist");
|
||||
} else {
|
||||
cy.get(".hosts-missing").should("not.exist");
|
||||
cy.get(".hosts-low-space").should("not.exist");
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "Windows":
|
||||
cy.getAttached(".dashboard-page__wrapper").within(() => {
|
||||
cy.findByText(/platform/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".operating-systems").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
cy.get(".activity-feed").should("not.exist");
|
||||
if (tier === "premium") {
|
||||
cy.getAttached(".hosts-missing").should("exist");
|
||||
cy.getAttached(".hosts-low-space").should("exist");
|
||||
} else {
|
||||
cy.get(".hosts-missing").should("not.exist");
|
||||
cy.get(".hosts-low-space").should("not.exist");
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "Linux":
|
||||
cy.getAttached(".dashboard-page__wrapper").within(() => {
|
||||
cy.findByText(/platform/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
cy.get(".activity-feed").should("not.exist");
|
||||
if (tier === "premium") {
|
||||
cy.getAttached(".hosts-missing").should("exist");
|
||||
cy.getAttached(".hosts-low-space").should("exist");
|
||||
} else {
|
||||
cy.get(".hosts-missing").should("not.exist");
|
||||
cy.get(".hosts-low-space").should("not.exist");
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "All":
|
||||
cy.getAttached(".dashboard-page__wrapper").within(() => {
|
||||
cy.findByText(/platform/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".activity-feed").should("exist");
|
||||
// hidden if no software
|
||||
cy.get(".home-software").should("not.exist");
|
||||
if (tier === "premium") {
|
||||
cy.getAttached(".hosts-missing").should("exist");
|
||||
cy.getAttached(".hosts-low-space").should("exist");
|
||||
} else {
|
||||
cy.get(".hosts-missing").should("not.exist");
|
||||
cy.get(".hosts-low-space").should("not.exist");
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// no activity feed on team dashboard
|
||||
cy.getAttached(".dashboard-page__wrapper").within(() => {
|
||||
cy.findByText(/platform/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
// hidden if no software
|
||||
cy.get(".home-software").should("not.exist");
|
||||
cy.get(".activity-feed").should("not.exist");
|
||||
if (tier === "premium") {
|
||||
cy.getAttached(".hosts-missing").should("exist");
|
||||
cy.getAttached(".hosts-low-space").should("exist");
|
||||
} else {
|
||||
cy.get(".hosts-missing").should("not.exist");
|
||||
cy.get(".hosts-low-space").should("not.exist");
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
verifiesFilteredHostByPlatform: (platform: string) => {
|
||||
if (platform === "none") {
|
||||
cy.findByText(/view all hosts/i).click();
|
||||
cy.findByRole("status", { name: /hosts filtered by/i }).should(
|
||||
"not.exist"
|
||||
);
|
||||
} else {
|
||||
cy.findByText(/view all hosts/i).click();
|
||||
cy.findByRole("status", {
|
||||
name: `hosts filtered by ${platform}`,
|
||||
}).should("exist");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default dashboardPage;
|
@ -1,46 +0,0 @@
|
||||
const hostDetailsPage = {
|
||||
visitsHostDetailsPage: (hostId: number) => {
|
||||
cy.visit(`/hosts/${hostId}`);
|
||||
},
|
||||
|
||||
verifiesTeamsisDisabled: () => {
|
||||
cy.findByText(/team/i).should("not.exist");
|
||||
},
|
||||
|
||||
verifiesTeam: (teamName: string) => {
|
||||
cy.getAttached(".info-flex").within(() => {
|
||||
// Team is shown for host
|
||||
cy.findByText(teamName).should("exist");
|
||||
});
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
},
|
||||
|
||||
allowsCreateOsPolicy: () => {
|
||||
cy.getAttached(".info-flex").within(() => {
|
||||
cy.findByText(/ubuntu/i).should("exist");
|
||||
cy.getAttached(".host-summary__os-policy-button").click();
|
||||
});
|
||||
cy.getAttached(".modal__content")
|
||||
.findByRole("button", { name: /create new policy/i })
|
||||
.should("be.enabled");
|
||||
},
|
||||
|
||||
hidesCreateOSPolicy: () => {
|
||||
cy.getAttached(".info-flex").within(() => {
|
||||
cy.findByText("Operating system")
|
||||
.next()
|
||||
.findByText(/ubuntu/i)
|
||||
.should("exist");
|
||||
|
||||
cy.findByText("Operating system")
|
||||
.next()
|
||||
.findByRole("button")
|
||||
.should("not.exist");
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default hostDetailsPage;
|
@ -1,57 +0,0 @@
|
||||
const manageHostsPage = {
|
||||
visitsManageHostsPage: () => {
|
||||
cy.visit("/hosts/manage");
|
||||
},
|
||||
|
||||
allowsManageAndAddSecrets: () => {
|
||||
cy.getAttached(".button-wrap")
|
||||
.contains("button", /manage enroll secret/i)
|
||||
.click();
|
||||
cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.contains("button", /add secret/i).click();
|
||||
cy.wait(500); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.contains("button", /save/i).click();
|
||||
cy.findByText(/successfully added/i);
|
||||
},
|
||||
|
||||
allowsAddHosts: () => {
|
||||
cy.getAttached(".button-wrap")
|
||||
.contains("button", /add hosts/i)
|
||||
.click();
|
||||
cy.getAttached(".modal__content").contains("button", /done/i).click();
|
||||
},
|
||||
|
||||
allowsAddLabelForm: () => {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.findByRole("button", { name: /add label/i }).click();
|
||||
cy.findByText(/new label/i).should("exist");
|
||||
cy.getAttached(".label-form__button-wrap")
|
||||
.contains("button", /cancel/i)
|
||||
.click();
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
if (text === "Add label") {
|
||||
cy.getAttached(".label-filter-select__control").click();
|
||||
cy.contains("button", /add label/i).should("not.exist");
|
||||
} else {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
}
|
||||
},
|
||||
|
||||
includesTeamColumn: () => {
|
||||
cy.getAttached("thead").within(() => {
|
||||
cy.findByText(/team/i).should("exist");
|
||||
});
|
||||
},
|
||||
|
||||
includesTeamDropdown: (teamName = "All teams") => {
|
||||
cy.getAttached(".Select-value-label").contains(teamName);
|
||||
},
|
||||
|
||||
verifiesTeamsIsDisabled: () => {
|
||||
cy.findByText(/teams/i).should("not.exist");
|
||||
},
|
||||
};
|
||||
|
||||
export default manageHostsPage;
|
@ -1,62 +0,0 @@
|
||||
const managePacksPage = {
|
||||
visitsManagePacksPage: () => {
|
||||
cy.visit("/packs/manage");
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
},
|
||||
|
||||
allowsCreatePack: () => {
|
||||
cy.getAttached(".empty-table__container");
|
||||
cy.findByRole("button", { name: /create new pack/i }).click();
|
||||
cy.findByLabelText(/name/i).click().type("Errors and crashes");
|
||||
cy.findByLabelText(/description/i)
|
||||
.click()
|
||||
.type("See all user errors and window crashes.");
|
||||
cy.findByRole("button", { name: /save query pack/i }).should("be.enabled");
|
||||
},
|
||||
|
||||
verifiesCreatedPack: () => {
|
||||
cy.findByRole("button", { name: /save query pack/i }).click();
|
||||
},
|
||||
|
||||
allowsEditPack: () => {
|
||||
cy.findByLabelText(/name/i).clear().type("Server errors");
|
||||
cy.findByLabelText(/description/i)
|
||||
.clear()
|
||||
.type("See all server errors.");
|
||||
cy.findByRole("button", { name: /save/i }).should("be.enabled");
|
||||
},
|
||||
|
||||
verifiesEditedPack: () => {
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
},
|
||||
|
||||
allowsDeletePack: () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
});
|
||||
});
|
||||
cy.findByRole("button", { name: /delete/i }).click();
|
||||
cy.getAttached(".remove-pack-modal .modal-cta-wrap > .button--alert")
|
||||
.contains("button", /delete/i)
|
||||
.should("be.enabled");
|
||||
},
|
||||
|
||||
verifiesDeletedPack: () => {
|
||||
cy.getAttached(".remove-pack-modal .modal-cta-wrap > .button--alert")
|
||||
.contains("button", /delete/i)
|
||||
.click({ force: true });
|
||||
cy.findByText(/successfully deleted/i).should("be.visible");
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.findByText(/windows starter pack/i).should("not.exist");
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default managePacksPage;
|
@ -1,115 +0,0 @@
|
||||
const managePoliciesPage = {
|
||||
visitManagePoliciesPage: () => {
|
||||
cy.visit("/policies/manage");
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
},
|
||||
|
||||
allowsAddDefaultPolicy: () => {
|
||||
cy.findByRole("button", { name: /add a policy/i }).click();
|
||||
// Add a default policy
|
||||
cy.findByText(/gatekeeper enabled/i).click();
|
||||
cy.getAttached(".policy-form__button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /run/i }).should("exist");
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
});
|
||||
},
|
||||
|
||||
verifiesAddedDefaultPolicy: () => {
|
||||
cy.getAttached(".modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /save policy/i }).click();
|
||||
});
|
||||
cy.findByText(/policy created/i).should("exist");
|
||||
cy.findByText(/gatekeeper enabled/i).should("exist");
|
||||
},
|
||||
|
||||
allowsAutomatePolicy: () => {
|
||||
cy.getAttached(".button-wrap")
|
||||
.findByRole("button", { name: /manage automations/i })
|
||||
.click();
|
||||
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
cy.getAttached("#webhook-url").clear().type("https://example.com/admin");
|
||||
});
|
||||
},
|
||||
|
||||
verifiesAutomatedPolicy: () => {
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
});
|
||||
cy.findByText(/successfully updated policy automations/i).should("exist");
|
||||
},
|
||||
|
||||
allowsDeletePolicy: () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").check({
|
||||
force: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.findByRole("button", { name: /delete/i }).click();
|
||||
cy.getAttached(".delete-policy-modal").within(() => {
|
||||
cy.findByRole("button", { name: /delete/i }).should("be.enabled");
|
||||
});
|
||||
},
|
||||
|
||||
verifiesDeletedPolicy: () => {
|
||||
cy.getAttached(".delete-policy-modal").within(() => {
|
||||
cy.findByRole("button", { name: /delete/i }).click();
|
||||
});
|
||||
cy.findByText(/deleted policy/i).should("exist");
|
||||
cy.findByText(/backup/i).should("not.exist");
|
||||
},
|
||||
|
||||
allowsSelectRunSavePolicy: (name = "gatekeeper") => {
|
||||
cy.getAttached(".data-table__table").within(() => {
|
||||
cy.findByRole("button", { name: RegExp(name, "i") }).click();
|
||||
});
|
||||
cy.getAttached(".policy-form__button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /run/i }).should("exist");
|
||||
cy.findByRole("button", { name: /save/i }).should("exist");
|
||||
});
|
||||
},
|
||||
|
||||
allowsViewPolicyOnly: () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.contains(".fleet-checkbox__input").should("not.exist");
|
||||
cy.findByRole("button", { name: /filevault/i }).click();
|
||||
});
|
||||
});
|
||||
cy.getAttached(".policy-form__wrapper").within(() => {
|
||||
cy.findByRole("button", { name: /run/i }).should("not.exist");
|
||||
cy.findByRole("button", { name: /save/i }).should("not.exist");
|
||||
});
|
||||
},
|
||||
|
||||
allowsRunSavePolicy: () => {
|
||||
cy.getAttached(".data-table__table").within(() => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /gatekeeper/i,
|
||||
}).click();
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.getAttached(".policy-form__button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /run/i }).should("exist");
|
||||
cy.findByRole("button", { name: /save/i }).should("exist");
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default managePoliciesPage;
|
@ -1,163 +0,0 @@
|
||||
import * as path from "path";
|
||||
import { format } from "date-fns";
|
||||
|
||||
const manageQueriesPage = {
|
||||
visitManageQueriesPage: () => {
|
||||
cy.visit("/queries/manage");
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
},
|
||||
|
||||
allowsCreateNewQuery: () => {
|
||||
cy.getAttached(".button--brand"); // ensures cta button loads
|
||||
cy.findByRole("button", { name: /new query/i }).click();
|
||||
cy.getAttached(".query-page__form .ace_scroller")
|
||||
.click({ force: true })
|
||||
.type("{selectall}SELECT * FROM windows_crashes;");
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.getAttached(".modal__background").within(() => {
|
||||
cy.getAttached(".modal__modal_container").within(() => {
|
||||
cy.getAttached(".modal__content").within(() => {
|
||||
cy.getAttached("form").within(() => {
|
||||
cy.findByLabelText(/name/i).click().type("Cypress test query");
|
||||
cy.findByLabelText(/description/i)
|
||||
.click()
|
||||
.type("Cypress test of create new query flow.");
|
||||
cy.findByLabelText(/observers can run/i).click({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
verifiesCreatedNewQuery: () => {
|
||||
cy.getAttached(".modal__background").within(() => {
|
||||
cy.getAttached(".modal__modal_container").within(() => {
|
||||
cy.getAttached(".modal__content").within(() => {
|
||||
cy.getAttached("form").within(() => {
|
||||
cy.findByRole("button", { name: /save query/i }).click();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.findByText(/query created/i).should("exist");
|
||||
cy.getAttached(".query-form__query-name").within(() => {
|
||||
cy.findByText(/cypress test query/i).should("exist");
|
||||
});
|
||||
},
|
||||
|
||||
allowsEditExistingQuery: () => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.getAttached(".query-page__form .ace_text-input")
|
||||
.click({ force: true })
|
||||
.clear({ force: true })
|
||||
.type("SELECT 1 FROM cypress;", {
|
||||
force: true,
|
||||
});
|
||||
},
|
||||
|
||||
verifiesEditedExistingQuery: () => {
|
||||
cy.findByRole("button", { name: "Save" }).click(); // we have 'save as new' also
|
||||
cy.findByText(/query updated/i).should("be.visible");
|
||||
},
|
||||
|
||||
allowsSaveAsNewQuery: () => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.findByText(/get authorized/i).click();
|
||||
});
|
||||
cy.findByRole("button", { name: /run query/i }).should("exist");
|
||||
cy.getAttached(".query-page__form .ace_scroller")
|
||||
.click()
|
||||
.type("{selectall}SELECT datetime, username FROM windows_crashes;");
|
||||
cy.findByRole("button", { name: /save as new/i }).should("be.enabled");
|
||||
},
|
||||
|
||||
verifiesSavedAsNewQuery: () => {
|
||||
cy.findByRole("button", { name: /save as new/i }).click();
|
||||
cy.findByText(/successfully added query/i).should("be.visible");
|
||||
cy.findByText(/copy of/i).should("be.visible");
|
||||
},
|
||||
|
||||
allowsDeleteExistingQuery: () => {
|
||||
cy.findByText(/detect presence of authorized ssh keys/i)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").check({
|
||||
force: true,
|
||||
});
|
||||
});
|
||||
cy.findByRole("button", { name: /delete/i }).click();
|
||||
cy.getAttached(".delete-query-modal .modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /delete/i }).should("exist");
|
||||
});
|
||||
},
|
||||
|
||||
verifiesDeletedExistingQuery: () => {
|
||||
cy.getAttached(".delete-query-modal .modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /delete/i }).click();
|
||||
});
|
||||
cy.findByText(/successfully deleted query/i).should("be.visible");
|
||||
cy.findByText(/detect presence of authorized ssh keys/i).should(
|
||||
"not.exist"
|
||||
);
|
||||
},
|
||||
|
||||
// TODO: Allows delete of self authored query only (Team Admin, team maintainer)
|
||||
|
||||
allowsSelectTeamTargets: () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.findAllByText(/detect presence/i).click();
|
||||
});
|
||||
|
||||
cy.getAttached(".query-form__button-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /run/i }).click();
|
||||
});
|
||||
cy.contains("h3", /teams/i).should("exist");
|
||||
cy.contains(".selector-name", /apples/i).should("exist");
|
||||
},
|
||||
|
||||
allowsRunQuery: () => {
|
||||
cy.getAttached(".name__cell .button--text-link").first().click();
|
||||
cy.findByRole("button", { name: /run query/i }).click();
|
||||
cy.findByText(/select targets/i).should("exist");
|
||||
cy.findByText(/all hosts/i).click();
|
||||
cy.findByText(/host targeted/i).should("exist"); // target count
|
||||
},
|
||||
|
||||
verifiesRanQuery: () => {
|
||||
cy.findByRole("button", { name: /run/i }).click();
|
||||
cy.findByText(/querying selected host/i).should("exist"); // target count
|
||||
},
|
||||
|
||||
allowsViewRanQuery: () => {
|
||||
// Ensures live query runs
|
||||
cy.wait(10000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.findByRole("button", { name: /show query/i }).click();
|
||||
});
|
||||
cy.getAttached(".show-query-modal").within(() => {
|
||||
cy.findByRole("button", { name: /done/i }).click();
|
||||
});
|
||||
},
|
||||
|
||||
allowsExportQueryResults: () => {
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.findByRole("button", { name: /export results/i }).click();
|
||||
const formattedTime = format(new Date(), "MM-dd-yy hh-mm-ss");
|
||||
const filename = `Query Results (${formattedTime}).csv`;
|
||||
cy.readFile(path.join(Cypress.config("downloadsFolder"), filename), {
|
||||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default manageQueriesPage;
|
@ -1,124 +0,0 @@
|
||||
const manageSchedulePage = {
|
||||
visitManageSchedulePage: () => {
|
||||
cy.visit("/schedule/manage");
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
if (text === "Advanced") {
|
||||
cy.getAttached(".empty-table__cta-buttons").within(() => {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
});
|
||||
} else cy.contains("button", text).should("not.exist");
|
||||
},
|
||||
|
||||
changesTeam: (team1: string, team2: string) => {
|
||||
cy.getAttached(".manage-schedule-page__header").within(() => {
|
||||
cy.contains(team1).click({ force: true });
|
||||
cy.contains(team2).click({ force: true });
|
||||
});
|
||||
},
|
||||
|
||||
confirmsTeam: (team: string) => {
|
||||
cy.getAttached(".manage-schedule-page__header-wrap").within(() => {
|
||||
cy.findByText(team).should("exist");
|
||||
});
|
||||
},
|
||||
|
||||
allowsAddSchedule: () => {
|
||||
cy.getAttached(".empty-table__cta-buttons").within(() => {
|
||||
cy.findByRole("button", { name: /schedule a query/i }).click({
|
||||
force: true,
|
||||
});
|
||||
});
|
||||
cy.getAttached(".schedule-editor-modal__form").within(() => {
|
||||
cy.findByText(/select query/i).click();
|
||||
cy.findByText(/get local/i).click();
|
||||
cy.findByText(/every day/i).click();
|
||||
cy.findByText(/every 6 hours/i).click();
|
||||
cy.findByText(/show advanced options/i).click();
|
||||
cy.findByText(/snapshot/i).click();
|
||||
cy.findByText(/ignore removals/i).click();
|
||||
cy.getAttached(".schedule-editor-modal__form-field--platform").within(
|
||||
() => {
|
||||
cy.findByText(/select/i).click();
|
||||
cy.findByText(/linux/i).click();
|
||||
}
|
||||
);
|
||||
cy.getAttached(".schedule-editor-modal__form-field--osquer-vers").within(
|
||||
() => {
|
||||
cy.findByText(/all/i).click();
|
||||
cy.findByText(/4.6.0/i).click();
|
||||
}
|
||||
);
|
||||
cy.getAttached(".schedule-editor-modal__form-field--shard").within(() => {
|
||||
cy.getAttached(".input-field").click().type("50");
|
||||
});
|
||||
cy.getAttached(".modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /schedule/i }).should("be.enabled");
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
verifiesAddedSchedule: () => {
|
||||
cy.getAttached(".modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /schedule/i }).click();
|
||||
});
|
||||
cy.findByText(/successfully added/i).should("be.visible");
|
||||
cy.getAttached("tbody>tr").should("have.length", 1);
|
||||
},
|
||||
|
||||
allowsEditSchedule: () => {
|
||||
cy.getAttached(".manage-schedule-page");
|
||||
cy.getAttached("tbody>tr")
|
||||
.should("have.length", 1)
|
||||
.within(() => {
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/edit/i).click();
|
||||
});
|
||||
cy.getAttached(".schedule-editor-modal__form").within(() => {
|
||||
cy.findByText(/every 6 hours/i).click();
|
||||
cy.findByText(/every day/i).click();
|
||||
|
||||
cy.getAttached(".modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /schedule/i }).should("be.enabled");
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
verifiesEditedSchedule: () => {
|
||||
cy.getAttached(".modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /schedule/i }).click();
|
||||
});
|
||||
cy.findByText(/successfully updated/i).should("be.visible");
|
||||
},
|
||||
|
||||
allowsRemoveSchedule: () => {
|
||||
cy.getAttached(".manage-schedule-page");
|
||||
cy.getAttached("tbody>tr")
|
||||
.should("have.length", 1)
|
||||
.within(() => {
|
||||
cy.getAttached(".Select-placeholder").within(() => {
|
||||
cy.findByText(/action/i).click();
|
||||
});
|
||||
cy.getAttached(".Select-menu").within(() => {
|
||||
cy.findByText(/remove/i).click();
|
||||
});
|
||||
});
|
||||
cy.getAttached(".remove-scheduled-query-modal .modal-cta-wrap").within(
|
||||
() => {
|
||||
cy.findByRole("button", { name: /remove/i }).should("be.enabled");
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
verifiesRemovedSchedule: () => {
|
||||
cy.getAttached(".remove-scheduled-query-modal .modal-cta-wrap").within(
|
||||
() => {
|
||||
cy.findByRole("button", { name: /remove/i }).click();
|
||||
}
|
||||
);
|
||||
cy.findByText(/successfully removed/i).should("be.visible");
|
||||
},
|
||||
};
|
||||
|
||||
export default manageSchedulePage;
|
@ -1,16 +0,0 @@
|
||||
const manageSoftwarePage = {
|
||||
visitManageSoftwarePage: () => {
|
||||
cy.visit("/software/manage");
|
||||
},
|
||||
|
||||
hidesButton: (text: string) => {
|
||||
cy.contains("button", text).should("not.exist");
|
||||
},
|
||||
|
||||
allowsManageAutomations: () => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
cy.findByRole("button", { name: /cancel/i }).click();
|
||||
},
|
||||
};
|
||||
|
||||
export default manageSoftwarePage;
|
@ -1,10 +0,0 @@
|
||||
const teamsDropdown = {
|
||||
switchTeams: (team1: string, team2: string) => {
|
||||
cy.getAttached(".component__team-dropdown").within(() => {
|
||||
cy.findByText(team1).click({ force: true });
|
||||
});
|
||||
cy.getAttached(".Select-menu").contains(team2).click({ force: true });
|
||||
},
|
||||
};
|
||||
|
||||
export default teamsDropdown;
|
@ -1,21 +0,0 @@
|
||||
const userProfilePage = {
|
||||
visitUserProfilePage: () => {
|
||||
cy.visit("/profile");
|
||||
},
|
||||
|
||||
showRole: (role: string, team?: string) => {
|
||||
cy.getAttached(".user-side-panel").within(() => {
|
||||
if (team) {
|
||||
cy.getAttached(".user-side-panel__header")
|
||||
.contains(/team/i)
|
||||
.next()
|
||||
.contains(team);
|
||||
} else {
|
||||
cy.findByText(/teams/i).should("not.exist");
|
||||
}
|
||||
cy.findByText("Role").next().contains(role);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default userProfilePage;
|
@ -1,23 +0,0 @@
|
||||
# Premium tier tests
|
||||
|
||||
These tests should only run when the server is in `premium` tier.
|
||||
|
||||
To enable the tests:
|
||||
|
||||
```sh
|
||||
export CYPRESS_FLEET_TIER=premium
|
||||
```
|
||||
|
||||
Before running the appropriate `yarn cypress (open|run)` command.
|
||||
|
||||
## Filtering
|
||||
|
||||
Any test suite in this directory should use the following pattern for filtering:
|
||||
|
||||
**FIXME**: There must be a better way to do this for all tests in the directory rather than having to add the check in each file?
|
||||
|
||||
```js
|
||||
if (Cypress.env("FLEET_TIER") === "premium") {
|
||||
// test suite here
|
||||
}
|
||||
```
|
@ -1,596 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import teamsDropdown from "../pages/teamsDropdown";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
|
||||
const { GOOD_PASSWORD, CONFIG_INTEGRATIONS_AUTOMATIONS } = CONSTANTS;
|
||||
|
||||
const patchTeamJiraPoliciesIntegration = {
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
project_key: "PROJECT 1",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: true,
|
||||
project_key: "PROJECT 2",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
group_id: 12345678,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
group_id: 87654321,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
failing_policies_webhook: {
|
||||
destination_url: "https://example.com/global_admin",
|
||||
enable_failing_policies_webhook: false,
|
||||
policy_ids: [1, 3, 2],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const getTeamJiraPoliciesIntegration = {
|
||||
team: {
|
||||
id: 1,
|
||||
created_at: "2022-07-01T19:31:46Z",
|
||||
name: "Apples",
|
||||
description: "",
|
||||
agent_options: {
|
||||
config: {
|
||||
options: {
|
||||
pack_delimiter: "/",
|
||||
logger_tls_period: 10,
|
||||
distributed_plugin: "tls",
|
||||
disable_distributed: false,
|
||||
logger_tls_endpoint: "/api/osquery/log",
|
||||
distributed_interval: 10,
|
||||
distributed_tls_max_attempts: 3,
|
||||
},
|
||||
decorators: {
|
||||
load: [
|
||||
"SELECT uuid AS host_uuid FROM system_info;",
|
||||
"SELECT hostname AS hostname FROM system_info;",
|
||||
],
|
||||
},
|
||||
},
|
||||
overrides: {},
|
||||
},
|
||||
webhook_settings: {
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://example.com/global_admin",
|
||||
policy_ids: [1, 3, 2],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
},
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
project_key: "PROJECT 1",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: true,
|
||||
project_key: "PROJECT 2",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
group_id: 12345678,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
group_id: 87654321,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
user_count: 0,
|
||||
users: [
|
||||
{
|
||||
created_at: "0001-01-01T00:00:00Z",
|
||||
updated_at: "0001-01-01T00:00:00Z",
|
||||
id: 8,
|
||||
name: "Marco",
|
||||
email: "marco@organization.com",
|
||||
force_password_reset: false,
|
||||
gravatar_url: "",
|
||||
sso_enabled: false,
|
||||
global_role: null,
|
||||
api_only: false,
|
||||
teams: null,
|
||||
role: "observer",
|
||||
},
|
||||
{
|
||||
created_at: "0001-01-01T00:00:00Z",
|
||||
updated_at: "0001-01-01T00:00:00Z",
|
||||
id: 9,
|
||||
name: "Anita T. Admin",
|
||||
email: "anita@organization.com",
|
||||
force_password_reset: false,
|
||||
gravatar_url: "",
|
||||
sso_enabled: false,
|
||||
global_role: null,
|
||||
api_only: false,
|
||||
teams: null,
|
||||
role: "admin",
|
||||
},
|
||||
{
|
||||
created_at: "0001-01-01T00:00:00Z",
|
||||
updated_at: "0001-01-01T00:00:00Z",
|
||||
id: 10,
|
||||
name: "Toni",
|
||||
email: "toni@organization.com",
|
||||
force_password_reset: false,
|
||||
gravatar_url: "",
|
||||
sso_enabled: false,
|
||||
global_role: null,
|
||||
api_only: false,
|
||||
teams: null,
|
||||
role: "observer",
|
||||
},
|
||||
],
|
||||
host_count: 0,
|
||||
secrets: [
|
||||
{
|
||||
secret: "OgkyoX/SGsuvLXPaNHUVIJoYSx1PTV+S",
|
||||
created_at: "2022-07-01T19:31:46Z",
|
||||
team_id: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const patchTeamZendeskPoliciesIntegration = {
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
project_key: "PROJECT 1",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
project_key: "PROJECT 2",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
group_id: 12345678,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: true,
|
||||
group_id: 87654321,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
failing_policies_webhook: {
|
||||
destination_url: "https://example.com/global_admin",
|
||||
enable_failing_policies_webhook: false,
|
||||
policy_ids: [1, 3, 2],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const getTeamZendeskPoliciesIntegration = {
|
||||
team: {
|
||||
id: 1,
|
||||
created_at: "2022-07-01T19:31:46Z",
|
||||
name: "Apples",
|
||||
description: "",
|
||||
agent_options: {
|
||||
config: {
|
||||
options: {
|
||||
pack_delimiter: "/",
|
||||
logger_tls_period: 10,
|
||||
distributed_plugin: "tls",
|
||||
disable_distributed: false,
|
||||
logger_tls_endpoint: "/api/osquery/log",
|
||||
distributed_interval: 10,
|
||||
distributed_tls_max_attempts: 3,
|
||||
},
|
||||
decorators: {
|
||||
load: [
|
||||
"SELECT uuid AS host_uuid FROM system_info;",
|
||||
"SELECT hostname AS hostname FROM system_info;",
|
||||
],
|
||||
},
|
||||
},
|
||||
overrides: {},
|
||||
},
|
||||
webhook_settings: {
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://example.com/global_admin",
|
||||
policy_ids: [1, 3, 2],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
},
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
project_key: "PROJECT 1",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
project_key: "PROJECT 2",
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
enable_failing_policies: false,
|
||||
group_id: 12345678,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
{
|
||||
enable_failing_policies: true,
|
||||
group_id: 87654321,
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
user_count: 0,
|
||||
users: [
|
||||
{
|
||||
created_at: "0001-01-01T00:00:00Z",
|
||||
updated_at: "0001-01-01T00:00:00Z",
|
||||
id: 8,
|
||||
name: "Marco",
|
||||
email: "marco@organization.com",
|
||||
force_password_reset: false,
|
||||
gravatar_url: "",
|
||||
sso_enabled: false,
|
||||
global_role: null,
|
||||
api_only: false,
|
||||
teams: null,
|
||||
role: "observer",
|
||||
},
|
||||
{
|
||||
created_at: "0001-01-01T00:00:00Z",
|
||||
updated_at: "0001-01-01T00:00:00Z",
|
||||
id: 9,
|
||||
name: "Anita T. Admin",
|
||||
email: "anita@organization.com",
|
||||
force_password_reset: false,
|
||||
gravatar_url: "",
|
||||
sso_enabled: false,
|
||||
global_role: null,
|
||||
api_only: false,
|
||||
teams: null,
|
||||
role: "admin",
|
||||
},
|
||||
{
|
||||
created_at: "0001-01-01T00:00:00Z",
|
||||
updated_at: "0001-01-01T00:00:00Z",
|
||||
id: 10,
|
||||
name: "Toni",
|
||||
email: "toni@organization.com",
|
||||
force_password_reset: false,
|
||||
gravatar_url: "",
|
||||
sso_enabled: false,
|
||||
global_role: null,
|
||||
api_only: false,
|
||||
teams: null,
|
||||
role: "observer",
|
||||
},
|
||||
],
|
||||
host_count: 0,
|
||||
secrets: [
|
||||
{
|
||||
secret: "OgkyoX/SGsuvLXPaNHUVIJoYSx1PTV+S",
|
||||
created_at: "2022-07-01T19:31:46Z",
|
||||
team_id: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
describe("Premium tier - Global Admin user", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPremium();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies("apples");
|
||||
cy.addDockerHost("apples"); // host not transferred
|
||||
cy.addDockerHost("oranges"); // host transferred between teams by global admin
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anna@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Navigation and dashboard", () => {
|
||||
beforeEach(() => dashboardPage.visitsDashboardPage());
|
||||
it("displays intended global admin top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs__tab--selected").within(() => {
|
||||
cy.findByText(/organization/i).should("exist");
|
||||
});
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/manage users/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs__tab--selected").within(() => {
|
||||
cy.findByText(/users/i).should("exist");
|
||||
});
|
||||
});
|
||||
// Premium dashboard feature
|
||||
it("filters missing hosts", () => {
|
||||
cy.findByText(/missing hosts/i).click();
|
||||
cy.getAttached(".manage-hosts__filter-dropdowns").within(() => {
|
||||
cy.findByText(/missing hosts/i).should("exist");
|
||||
});
|
||||
});
|
||||
// Premium dashboard feature
|
||||
it("filters low disk space hosts", () => {
|
||||
cy.findByText(/low disk space hosts/i).click();
|
||||
cy.findByRole("status", {
|
||||
name: /hosts filtered by low disk space/i,
|
||||
}).should("exist");
|
||||
});
|
||||
});
|
||||
// Global Admin dashboard tested in integration/free/admin.spec.ts
|
||||
// Team Admin dashboard tested below in integration/premium/admin.spec.ts
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => manageHostsPage.visitsManageHostsPage());
|
||||
it("verifies teams is enabled on Manage host page", () => {
|
||||
manageHostsPage.includesTeamColumn();
|
||||
});
|
||||
it("allows global admin to see and click all CTA buttons", () => {
|
||||
manageHostsPage.allowsAddHosts();
|
||||
manageHostsPage.allowsAddLabelForm();
|
||||
manageHostsPage.allowsManageAndAddSecrets();
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => hostDetailsPage.visitsHostDetailsPage(1));
|
||||
it("allows global admin to create an operating system policy", () => {
|
||||
hostDetailsPage.allowsCreateOsPolicy();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => {
|
||||
manageSoftwarePage.visitManageSoftwarePage();
|
||||
});
|
||||
// it(`displays "Probability of exploit" column`, () => {
|
||||
// cy.getAttached("thead").within(() => {
|
||||
// cy.findByText(/vulnerabilities/i).should("not.exist");
|
||||
// cy.findByText(/probability of exploit/i).should("exist");
|
||||
// });
|
||||
// });
|
||||
it("allows admin to click 'Manage automations' button", () => {
|
||||
manageSoftwarePage.allowsManageAutomations();
|
||||
});
|
||||
it("hides manage automations button since all teams not selected", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
beforeEach(() => manageQueriesPage.visitManageQueriesPage());
|
||||
it("allows global admin to select teams targets for query", () => {
|
||||
manageQueriesPage.allowsSelectTeamTargets();
|
||||
});
|
||||
// TODO: Allowed to delete self-authored query only
|
||||
});
|
||||
// Global Admin schedule tested in integration/free/admin.spec.ts
|
||||
// Team Admin team schedule tested below in integration/premium/admin.spec.ts
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => managePoliciesPage.visitManagePoliciesPage());
|
||||
it("allows global admin to add a new policy", () => {
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
it("allows global admin to automate a global policy", () => {
|
||||
managePoliciesPage.allowsAutomatePolicy();
|
||||
managePoliciesPage.verifiesAutomatedPolicy();
|
||||
});
|
||||
it("allows global admin to automate a team policy webhook", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.allowsAutomatePolicy();
|
||||
managePoliciesPage.verifiesAutomatedPolicy();
|
||||
});
|
||||
|
||||
it("allows global admin to delete a team policy", () => {
|
||||
cy.visit("/policies/manage");
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
});
|
||||
it("allows global admin to edit a team policy", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.allowsSelectRunSavePolicy("filevault");
|
||||
});
|
||||
});
|
||||
describe("Manage policies page (mock integrations)", () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/config",
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS
|
||||
).as("getIntegrations");
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.wait("@getIntegrations").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
});
|
||||
it("allows global admin to delete team policy", () => {
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
});
|
||||
it("allows global admin to automate a team policy jira integration", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage;
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
cy.getAttached(".button-wrap")
|
||||
.findByRole("button", { name: /manage automations/i })
|
||||
.click();
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
cy.findByText(/select integration/i).click();
|
||||
cy.findByText(/project 2/i).click();
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/teams/1",
|
||||
patchTeamJiraPoliciesIntegration
|
||||
).as("enableJiraPoliciesIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/teams/1",
|
||||
getTeamJiraPoliciesIntegration
|
||||
).as("enabledJiraPoliciesIntegration");
|
||||
cy.findByText(/save/i).click();
|
||||
});
|
||||
cy.findByText(/successfully updated policy automations/i).should("exist");
|
||||
});
|
||||
|
||||
it("allows global admin to automate a team policy zendesk integration", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
cy.getAttached(".button-wrap")
|
||||
.findByRole("button", { name: /manage automations/i })
|
||||
.click();
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
cy.getAttached("#ticket-radio-btn").next().click();
|
||||
cy.findByText(/select integration/i).click();
|
||||
cy.findByText(/87654321/i).click();
|
||||
cy.intercept(
|
||||
"PATCH",
|
||||
"/api/latest/fleet/teams/1",
|
||||
patchTeamZendeskPoliciesIntegration
|
||||
).as("enableZendeskPoliciesIntegration");
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/latest/fleet/teams/1",
|
||||
getTeamZendeskPoliciesIntegration
|
||||
).as("enabledZendeskPoliciesIntegration");
|
||||
cy.findByText(/save/i).click();
|
||||
cy.wait("@enableZendeskPoliciesIntegration").then((configStub) => {
|
||||
console.log(JSON.stringify(configStub));
|
||||
});
|
||||
});
|
||||
cy.findByText(/successfully updated policy automations/i).should("exist");
|
||||
});
|
||||
});
|
||||
describe("Admin settings page", () => {
|
||||
beforeEach(() => cy.visit("/settings/organization"));
|
||||
it("allows global admin to access team settings", () => {
|
||||
cy.getAttached(".react-tabs").within(() => {
|
||||
cy.findByText(/teams/i).click();
|
||||
});
|
||||
// Access the Settings - Team details page
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached(".name__cell .button--text-link")
|
||||
.eq(0)
|
||||
.within(() => {
|
||||
cy.findByText(/apples/i).click();
|
||||
});
|
||||
});
|
||||
cy.findByText(/apples/i).should("exist");
|
||||
cy.findByText(/manage users with global access here/i).should("exist");
|
||||
});
|
||||
it("displays the 'Team' section in the create user modal", () => {
|
||||
cy.getAttached(".react-tabs").within(() => {
|
||||
cy.findByText(/users/i).click();
|
||||
});
|
||||
cy.findByRole("button", { name: /create user/i }).click({ force: true });
|
||||
cy.findByText(/assign teams/i).should("exist");
|
||||
});
|
||||
it("allows global admin to edit existing user password", () => {
|
||||
cy.visit("/settings/users");
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.contains("Oliver") // case-sensitive
|
||||
.parent()
|
||||
.next()
|
||||
.next()
|
||||
.next()
|
||||
.next()
|
||||
.next()
|
||||
.within(() => cy.getAttached(".Select-placeholder").click());
|
||||
});
|
||||
cy.getAttached(".Select-menu").within(() => {
|
||||
cy.findByText(/edit/i).click();
|
||||
});
|
||||
cy.getAttached(".create-user-form").within(() => {
|
||||
cy.findByLabelText(/email/i).should("exist");
|
||||
cy.findByLabelText(/password/i).should("exist");
|
||||
});
|
||||
});
|
||||
it("allows access to Fleet Desktop settings", () => {
|
||||
cy.visit("settings/organization");
|
||||
cy.findByRole("navigation", { name: "settings" }).within(() => {
|
||||
cy.findByText(/organization info/i).should("exist");
|
||||
cy.findByText(/fleet desktop/i)
|
||||
.should("exist")
|
||||
.click();
|
||||
});
|
||||
cy.getAttached("[id=transparency_url")
|
||||
.should("have.value", "https://fleetdm.com/transparency")
|
||||
.clear()
|
||||
.type("http://example.com/transparency");
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.findByText(/successfully updated/i).should("exist");
|
||||
cy.visit("settings/organization/fleet-desktop");
|
||||
cy.getAttached("[id=transparency_url").should(
|
||||
"have.value",
|
||||
"http://example.com/transparency"
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
it("verifies admin user role and global access", () => {
|
||||
userProfilePage.visitUserProfilePage();
|
||||
userProfilePage.showRole("Admin", "Global");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,33 +0,0 @@
|
||||
const fakeDeviceToken = "phAK3d3vIC37OK3n";
|
||||
|
||||
describe("Fleet Desktop", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.addDockerHost();
|
||||
cy.setDesktopToken(1, fakeDeviceToken);
|
||||
cy.viewport(1200, 660);
|
||||
cy.seedPolicies();
|
||||
});
|
||||
after(() => {
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
describe("Fleet Desktop device user page", () => {
|
||||
beforeEach(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.visit(`/device/${fakeDeviceToken}`);
|
||||
});
|
||||
it("renders policies and provides instructions for self-remediation", () => {
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/policies/i).click();
|
||||
});
|
||||
cy.getAttached(".section--policies").within(() => {
|
||||
cy.findByText(/is filevault enabled/i).click();
|
||||
});
|
||||
cy.getAttached(".policy-details-modal").within(() => {
|
||||
cy.findByText(/click turn on filevault/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,127 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import teamsDropdown from "../pages/teamsDropdown";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe("Premium tier - Maintainer user", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPremium();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies("apples");
|
||||
cy.addDockerHost("apples");
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
describe("Global maintainer", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("mary@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => cy.visit("/dashboard"));
|
||||
it("displays intended global maintainer top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/manage users/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => dashboardPage.visitsDashboardPage());
|
||||
it("displays cards for all platforms and does not filter host platform", () => {
|
||||
dashboardPage.displaysCards("All", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("none");
|
||||
});
|
||||
it("displays cards for windows only and filters hosts by Windows platform", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Windows");
|
||||
});
|
||||
it("displays cards for linux only and filters hosts by Linux platform", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Linux");
|
||||
});
|
||||
it("displays cards for macOS only and filters hosts by macOS platform", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("macOS");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => manageHostsPage.visitsManageHostsPage());
|
||||
it("renders team elements", () => {
|
||||
manageHostsPage.includesTeamDropdown();
|
||||
manageHostsPage.includesTeamColumn();
|
||||
});
|
||||
it("renders 'Add hosts', 'Add label', and 'Manage enroll secrets' buttons", () => {
|
||||
manageHostsPage.allowsAddLabelForm();
|
||||
manageHostsPage.allowsAddHosts();
|
||||
manageHostsPage.allowsManageAndAddSecrets();
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => {
|
||||
hostDetailsPage.visitsHostDetailsPage(1);
|
||||
});
|
||||
it("allows global maintainer to create an operating system policy", () => {
|
||||
hostDetailsPage.allowsCreateOsPolicy();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => manageSoftwarePage.visitManageSoftwarePage());
|
||||
it("hides 'Manage automations' button from global maintainer", () => {
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
beforeEach(() => manageQueriesPage.visitManageQueriesPage());
|
||||
it("allows global maintainer to select teams targets for query", () => {
|
||||
manageQueriesPage.allowsSelectTeamTargets();
|
||||
});
|
||||
// TODO: Allowed to delete self-authored query only
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => managePoliciesPage.visitManagePoliciesPage());
|
||||
it("hides manage automations button", () => {
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
});
|
||||
it("allows global maintainer to add a new policy", () => {
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
it("allows global maintainer to delete a team policy", () => {
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
});
|
||||
it("allows global maintainer to edit a team policy", () => {
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.allowsSelectRunSavePolicy("filevault");
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
it("verifies user role and global access", () => {
|
||||
userProfilePage.visitUserProfilePage();
|
||||
userProfilePage.showRole("Maintainer", "Global");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,173 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import managePacksPage from "../pages/managePacksPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import manageSchedulePage from "../pages/manageSchedulePage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import teamsDropdown from "../pages/teamsDropdown";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe("Premium tier - Observer user", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPremium();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies("apples");
|
||||
cy.addDockerHost("apples");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
describe("Global observer", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("oliver@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => cy.visit("/dashboard"));
|
||||
it("displays intended global observer top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("not.exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/manage users/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => dashboardPage.visitsDashboardPage());
|
||||
it("displays cards for all platforms and does not filter host platform", () => {
|
||||
dashboardPage.displaysCards("All", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("none");
|
||||
});
|
||||
it("displays cards for windows only and filters hosts by Windows platform", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Windows");
|
||||
});
|
||||
it("displays cards for linux only and filters hosts by Linux platform", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Linux");
|
||||
});
|
||||
it("displays cards for macOS only and filters hosts by macOS platform", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("macOS");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => manageHostsPage.visitsManageHostsPage());
|
||||
it("renders team elements", () => {
|
||||
manageHostsPage.includesTeamDropdown();
|
||||
manageHostsPage.includesTeamColumn();
|
||||
});
|
||||
it("hides 'Add hosts', 'Add label', and 'Manage enroll secrets' buttons", () => {
|
||||
manageHostsPage.hidesButton("Add label");
|
||||
manageHostsPage.hidesButton("Add hosts");
|
||||
manageHostsPage.hidesButton("Manage enroll secret");
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => hostDetailsPage.visitsHostDetailsPage(1));
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
hostDetailsPage.verifiesTeam("Apples");
|
||||
hostDetailsPage.hidesCreateOSPolicy();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => manageSoftwarePage.visitManageSoftwarePage());
|
||||
it("hides manage automations button", () => {
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
beforeEach(() => manageQueriesPage.visitManageQueriesPage());
|
||||
it("allows global observer to select teams targets for query", () => {
|
||||
manageQueriesPage.allowsSelectTeamTargets();
|
||||
});
|
||||
});
|
||||
describe("Policies pages", () => {
|
||||
beforeEach(() => managePoliciesPage.visitManagePoliciesPage());
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
// No global policies seeded, placeholder displayed
|
||||
cy.findByText(/ask yes or no questions/i).should("exist");
|
||||
cy.findByText(/all your hosts/i).should("exist");
|
||||
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
managePoliciesPage.hidesButton("Add a policy");
|
||||
|
||||
teamsDropdown.switchTeams("All teams", "Apples");
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
managePoliciesPage.hidesButton("Add a policy");
|
||||
|
||||
managePoliciesPage.allowsViewPolicyOnly();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Team observer", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("toni@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Nav restrictions", () => {
|
||||
it("should restrict navigation according to role-based access controls", () => {
|
||||
// cypress tends to fail on uncaught exceptions. since we have
|
||||
// our own error handling, it's suggested to use this block to
|
||||
// suppress so the tests will keep running
|
||||
Cypress.on("uncaught:exception", () => {
|
||||
return false;
|
||||
});
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/schedule/i).should("not.exist");
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
manageSchedulePage.visitManageSchedulePage();
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
manageHostsPage.includesTeamColumn();
|
||||
manageHostsPage.hidesButton("Add hosts");
|
||||
manageHostsPage.hidesButton("Manage enroll secret");
|
||||
manageHostsPage.hidesButton("Add label");
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
it("hides 'Add a policy'", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
managePoliciesPage.hidesButton("Add a policy");
|
||||
cy.findByText(/all teams/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
describe("Policy detail page", () => {
|
||||
it("allows viewing policies only", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
managePoliciesPage.allowsViewPolicyOnly();
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
it("verifies observer role and team", () => {
|
||||
userProfilePage.visitUserProfilePage();
|
||||
userProfilePage.showRole("Observer", "Apples");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,55 +0,0 @@
|
||||
describe("SSO Sessions", () => {
|
||||
describe("JIT user provisioning", () => {
|
||||
before(() => {
|
||||
cy.setup();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
});
|
||||
|
||||
it("non-existent users can't login if JIT is not enabled", () => {
|
||||
cy.login();
|
||||
cy.setupSSO({
|
||||
enable_sso_idp_login: true,
|
||||
enable_jit_provisioning: false,
|
||||
});
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
// Log in
|
||||
cy.contains("button", "Sign on with SimpleSAML");
|
||||
cy.loginSSO({ username: "sso_user2" });
|
||||
cy.url().should("include", "/login?status=account_invalid");
|
||||
cy.getAttached(".flash-message");
|
||||
});
|
||||
|
||||
it("non-existent users are provisioned if JIT is enabled", () => {
|
||||
cy.login();
|
||||
cy.setupSSO({
|
||||
enable_sso_idp_login: true,
|
||||
enable_jit_provisioning: true,
|
||||
});
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
// Log in
|
||||
cy.contains("button", "Sign on with SimpleSAML");
|
||||
cy.loginSSO({ username: "sso_user2" });
|
||||
cy.contains("Hosts");
|
||||
cy.contains("was added to Fleet by SSO");
|
||||
});
|
||||
|
||||
it("existing users can log-in normally with JIT enabled", () => {
|
||||
cy.login();
|
||||
cy.setupSSO({
|
||||
enable_sso_idp_login: true,
|
||||
enable_jit_provisioning: true,
|
||||
});
|
||||
cy.logout();
|
||||
cy.visit("/");
|
||||
// Log in
|
||||
cy.contains("button", "Sign on with SimpleSAML");
|
||||
cy.loginSSO({ username: "sso_user" });
|
||||
cy.contains("Hosts");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,213 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
import hostDetailsPage from "../pages/hostDetailsPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageQueriesPage from "../pages/manageQueriesPage";
|
||||
import manageSchedulePage from "../pages/manageSchedulePage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe("Premium tier - Team Admin user", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPremium();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies("apples");
|
||||
cy.addDockerHost("apples"); // host not transferred
|
||||
cy.addDockerHost("oranges"); // host transferred between teams by global admin
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("anita@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => cy.visit("/dashboard"));
|
||||
it("displays intended team admin top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/manage users/i).should("not.exist");
|
||||
cy.findByText(/settings/i).click();
|
||||
});
|
||||
cy.getAttached(".react-tabs__tab--selected").within(() => {
|
||||
cy.findByText(/members/i).should("exist");
|
||||
});
|
||||
cy.getAttached(".react-tabs__tab-list").within(() => {
|
||||
cy.findByText(/agent options/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => cy.visit("/dashboard"));
|
||||
it("displays cards for team only, no activity card, and does not filter host platform", () => {
|
||||
dashboardPage.displaysCards("team", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("none");
|
||||
});
|
||||
it("displays cards for windows only and filters hosts by Windows platform", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Windows");
|
||||
});
|
||||
it("displays cards for linux only and filters hosts by Linux platform", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("Linux");
|
||||
});
|
||||
it("displays cards for macOS only and filters hosts by macOS platform", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS", "premium");
|
||||
dashboardPage.verifiesFilteredHostByPlatform("macOS");
|
||||
});
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
beforeEach(() => {
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
manageHostsPage.includesTeamColumn();
|
||||
manageHostsPage.allowsAddHosts();
|
||||
manageHostsPage.allowsManageAndAddSecrets();
|
||||
});
|
||||
});
|
||||
describe("Host details page", () => {
|
||||
beforeEach(() => hostDetailsPage.visitsHostDetailsPage(1));
|
||||
it("allows team admin to create an operating system policy", () => {
|
||||
hostDetailsPage.allowsCreateOsPolicy();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => manageSoftwarePage.visitManageSoftwarePage());
|
||||
it("hides manage automations button", () => {
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
beforeEach(() => manageQueriesPage.visitManageQueriesPage());
|
||||
it("allows team admin to select teams targets for query", () => {
|
||||
manageQueriesPage.allowsSelectTeamTargets();
|
||||
});
|
||||
it("disables team admin from deleting or editing a query not authored by them", () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getAttached(".fleet-checkbox__input").should("be.disabled");
|
||||
});
|
||||
cy.findAllByText(/detect presence/i).click();
|
||||
});
|
||||
cy.findByRole("button", { name: "Save" }).should("be.disabled");
|
||||
});
|
||||
});
|
||||
describe("Manage schedules page", () => {
|
||||
beforeEach(() => {
|
||||
manageSchedulePage.visitManageSchedulePage();
|
||||
});
|
||||
it("hides advanced button when team admin", () => {
|
||||
manageSchedulePage.confirmsTeam("Apples");
|
||||
manageSchedulePage.hidesButton("Advanced");
|
||||
});
|
||||
it("creates a new team scheduled query", () => {
|
||||
manageSchedulePage.allowsAddSchedule();
|
||||
manageSchedulePage.verifiesAddedSchedule();
|
||||
});
|
||||
it("edit a team's scheduled query successfully", () => {
|
||||
manageSchedulePage.allowsEditSchedule();
|
||||
manageSchedulePage.verifiesEditedSchedule();
|
||||
});
|
||||
it("remove a team's scheduled query successfully", () => {
|
||||
manageSchedulePage.allowsRemoveSchedule();
|
||||
manageSchedulePage.verifiesRemovedSchedule();
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
beforeEach(() => managePoliciesPage.visitManagePoliciesPage());
|
||||
it("allows team admin to add a new policy", () => {
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
it("allows team admin to edit a team policy", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
managePoliciesPage.allowsSelectRunSavePolicy();
|
||||
});
|
||||
it("allows team admin to automate a team policy", () => {
|
||||
managePoliciesPage.allowsAutomatePolicy();
|
||||
managePoliciesPage.verifiesAutomatedPolicy();
|
||||
});
|
||||
it("allows team admin to delete a team policy", () => {
|
||||
managePoliciesPage.allowsDeletePolicy();
|
||||
});
|
||||
});
|
||||
describe("Team admin settings page", () => {
|
||||
beforeEach(() => cy.visit("/settings/teams/1/members"));
|
||||
it("allows team admin to access team settings", () => {
|
||||
// Access the Settings - Team details page
|
||||
cy.findByText(/apples/i).should("exist");
|
||||
});
|
||||
it("displays the team admin controls", () => {
|
||||
cy.findByRole("button", { name: /create user/i }).click({ force: true });
|
||||
cy.findByRole("button", { name: /cancel/i }).click();
|
||||
cy.findByRole("button", { name: /add hosts/i }).click();
|
||||
cy.findByRole("button", { name: /done/i }).click();
|
||||
cy.findByRole("button", { name: /manage enroll secrets/i }).click();
|
||||
cy.findByRole("button", { name: /done/i }).click();
|
||||
});
|
||||
it("allows team admin to edit a team member", () => {
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr");
|
||||
cy.contains("Toni") // case-sensitive
|
||||
.parent()
|
||||
.next()
|
||||
.within(() => {
|
||||
cy.findByText(/observer/i).should("exist");
|
||||
})
|
||||
.next()
|
||||
.next()
|
||||
.within(() => {
|
||||
cy.findByText(/action/i).click();
|
||||
cy.findByText(/edit/i).click();
|
||||
});
|
||||
});
|
||||
cy.getAttached(".select-role-form__role-dropdown").within(() => {
|
||||
cy.findByText(/observer/i).click();
|
||||
cy.findByText(/maintainer/i).click();
|
||||
});
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr");
|
||||
cy.contains("Toni") // case-sensitive
|
||||
.parent()
|
||||
.next()
|
||||
.within(() => {
|
||||
cy.findByText(/maintainer/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
it("allows team admin to edit team name", () => {
|
||||
cy.findByRole("button", { name: /edit team/i }).click();
|
||||
cy.findByLabelText(/team name/i)
|
||||
.clear()
|
||||
.type("Mystic");
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.findByText(/updated team name/i).should("exist");
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
userProfilePage.visitUserProfilePage();
|
||||
userProfilePage.showRole("Admin", "Mystic");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,220 +0,0 @@
|
||||
import CONSTANTS from "../../support/constants";
|
||||
import dashboardPage from "../pages/dashboardPage";
|
||||
import manageHostsPage from "../pages/manageHostsPage";
|
||||
import managePacksPage from "../pages/managePacksPage";
|
||||
import managePoliciesPage from "../pages/managePoliciesPage";
|
||||
import manageSchedulePage from "../pages/manageSchedulePage";
|
||||
import manageSoftwarePage from "../pages/manageSoftwarePage";
|
||||
import teamsDropdown from "../pages/teamsDropdown";
|
||||
import userProfilePage from "../pages/userProfilePage";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
describe("Premium tier - Team observer/maintainer user", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPremium();
|
||||
cy.seedQueries();
|
||||
cy.seedPolicies("apples");
|
||||
cy.addDockerHost("apples");
|
||||
cy.addDockerHost("oranges");
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
cy.stopDockerHost();
|
||||
});
|
||||
describe("Team maintainer and team observer", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("marco@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => cy.visit("/dashboard"));
|
||||
it("displays intended team maintainer and team observer top navigation", () => {
|
||||
cy.getAttached(".site-nav-container").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/software/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/policies/i).should("exist");
|
||||
cy.getAttached(".user-menu").click();
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/manage users/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Dashboard", () => {
|
||||
beforeEach(() => dashboardPage.visitsDashboardPage());
|
||||
it("displays cards for all platforms", () => {
|
||||
dashboardPage.displaysCards("team", "premium");
|
||||
});
|
||||
it("displays cards for windows only", () => {
|
||||
dashboardPage.switchesPlatform("Windows");
|
||||
dashboardPage.displaysCards("Windows", "premium");
|
||||
});
|
||||
it("displays cards for linux only", () => {
|
||||
dashboardPage.switchesPlatform("Linux");
|
||||
dashboardPage.displaysCards("Linux", "premium");
|
||||
});
|
||||
it("displays cards for macOS only", () => {
|
||||
dashboardPage.switchesPlatform("macOS");
|
||||
dashboardPage.displaysCards("macOS", "premium");
|
||||
});
|
||||
it("views all hosts for all platforms", () => {
|
||||
cy.findByText(/view all hosts/i).click();
|
||||
cy.findByRole("status", { name: /hosts filtered by/i }).should(
|
||||
"not.exist"
|
||||
);
|
||||
});
|
||||
it("views all hosts for windows only", () => {
|
||||
cy.getAttached(".dashboard-page__platforms").within(() => {
|
||||
cy.getAttached(".Select-control").click();
|
||||
cy.findByText(/windows/i).click();
|
||||
});
|
||||
cy.findByText(/view all hosts/i).click();
|
||||
cy.findByRole("status", { name: /hosts filtered by Windows/i }).should(
|
||||
"exist"
|
||||
);
|
||||
});
|
||||
it("views all hosts for linux only", () => {
|
||||
cy.getAttached(".dashboard-page__platforms").within(() => {
|
||||
cy.getAttached(".Select-control").click();
|
||||
cy.findByText(/linux/i).click();
|
||||
});
|
||||
cy.findByText(/view all hosts/i).click();
|
||||
cy.findByRole("status", { name: /hosts filtered by Linux/i }).should(
|
||||
"exist"
|
||||
);
|
||||
});
|
||||
it("views all hosts for macOS only", () => {
|
||||
cy.getAttached(".dashboard-page__platforms").within(() => {
|
||||
cy.getAttached(".Select-control").click();
|
||||
cy.findByText(/macos/i).click();
|
||||
});
|
||||
cy.findByText(/view all hosts/i).click();
|
||||
cy.findByRole("status", { name: /hosts filtered by macOS/i }).should(
|
||||
"exist"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Team observer", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("marco@organization.com", GOOD_PASSWORD);
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
|
||||
cy.contains(/apples/i).should("exist");
|
||||
manageHostsPage.includesTeamColumn();
|
||||
|
||||
manageHostsPage.hidesButton("Add label");
|
||||
manageHostsPage.hidesButton("Add hosts");
|
||||
manageHostsPage.hidesButton("Manage enroll secrets");
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
it("hides 'Manage automation' and 'Add a policy' buttons", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
cy.contains(/apples/i).should("exist");
|
||||
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
managePoliciesPage.hidesButton("Add a policy");
|
||||
});
|
||||
});
|
||||
describe("Policy detail page", () => {
|
||||
it("allows view policy only", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
managePoliciesPage.allowsViewPolicyOnly();
|
||||
});
|
||||
});
|
||||
// nav restrictions are at the end because we expect to see a
|
||||
// 403 error overlay which will hide the nav and make the test fail
|
||||
describe("Nav restrictions", () => {
|
||||
it("should restrict navigation according to role-based access controls", () => {
|
||||
dashboardPage.visitsDashboardPage();
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.visit("/settings/organization");
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
managePacksPage.visitsManagePacksPage();
|
||||
cy.findByText(/you do not have permissions/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Team maintainer", () => {
|
||||
// cypress tends to fail on uncaught exceptions. since we have
|
||||
// our own error handling, it's suggested to use this block to
|
||||
// suppress so the tests will keep running
|
||||
Cypress.on("uncaught:exception", () => {
|
||||
return false;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession("marco@organization.com", GOOD_PASSWORD);
|
||||
manageHostsPage.visitsManageHostsPage();
|
||||
});
|
||||
describe("Manage hosts page", () => {
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
manageHostsPage.includesTeamColumn();
|
||||
manageHostsPage.hidesButton("Add label");
|
||||
|
||||
// On maintaining team, see the "add hosts" and "Manage enroll secret" buttons
|
||||
teamsDropdown.switchTeams("Apples", "Oranges");
|
||||
manageHostsPage.includesTeamDropdown("Oranges");
|
||||
manageHostsPage.allowsAddHosts();
|
||||
manageHostsPage.allowsManageAndAddSecrets();
|
||||
});
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => manageSoftwarePage.visitManageSoftwarePage());
|
||||
it("hides manage automations button", () => {
|
||||
manageSoftwarePage.hidesButton("Manage automations");
|
||||
});
|
||||
});
|
||||
describe("Manage schedule page", () => {
|
||||
it("should render elements according to role-based access controls", () => {
|
||||
manageSchedulePage.visitManageSchedulePage();
|
||||
manageSchedulePage.confirmsTeam("Oranges");
|
||||
manageSchedulePage.hidesButton("Advanced");
|
||||
manageSchedulePage.allowsAddSchedule();
|
||||
manageSchedulePage.verifiesAddedSchedule();
|
||||
});
|
||||
});
|
||||
describe("Manage policies page", () => {
|
||||
it("allows team maintainer to add, edit a policy, but not manage automation", () => {
|
||||
managePoliciesPage.visitManagePoliciesPage();
|
||||
teamsDropdown.switchTeams("Apples", "Oranges");
|
||||
|
||||
managePoliciesPage.hidesButton("Manage automations");
|
||||
managePoliciesPage.allowsAddDefaultPolicy();
|
||||
managePoliciesPage.verifiesAddedDefaultPolicy();
|
||||
});
|
||||
});
|
||||
describe("User profile page", () => {
|
||||
it("verifies user role and team", () => {
|
||||
userProfilePage.visitUserProfilePage();
|
||||
userProfilePage.showRole("Various", "2 teams");
|
||||
});
|
||||
});
|
||||
// nav restrictions are at the end because we expect to see a
|
||||
// 403 error overlay which will hide the nav and make the test fail
|
||||
describe("Nav restrictions", () => {
|
||||
it("should restrict navigation according to role-based access controls", () => {
|
||||
dashboardPage.visitsDashboardPage();
|
||||
|
||||
cy.contains("h2", "Hosts").should("exist");
|
||||
cy.getAttached("nav").within(() => {
|
||||
cy.findByText(/hosts/i).should("exist");
|
||||
cy.findByText(/queries/i).should("exist");
|
||||
cy.findByText(/schedule/i).should("exist");
|
||||
cy.findByText(/packs/i).should("not.exist");
|
||||
cy.findByText(/settings/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,147 +0,0 @@
|
||||
import manageSchedulePage from "../pages/manageSchedulePage";
|
||||
|
||||
describe("Teams flow (empty)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
describe("Teams settings page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/settings/teams");
|
||||
});
|
||||
it("creates a new team", () => {
|
||||
cy.getAttached(".empty-table__cta-buttons").within(() => {
|
||||
cy.contains("button", /create team/i).click();
|
||||
});
|
||||
cy.findByLabelText(/team name/i)
|
||||
.click()
|
||||
.type("Valor");
|
||||
cy.getAttached(".create-team-modal .modal-cta-wrap").within(() => {
|
||||
// ^$ forces exact match
|
||||
cy.findByRole("button", { name: /^create$/i }).click();
|
||||
});
|
||||
cy.findByText(/successfully created valor/i).should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Teams flow (seeded)", () => {
|
||||
before(() => {
|
||||
Cypress.session.clearAllSavedSessions();
|
||||
cy.setup();
|
||||
cy.loginWithCySession();
|
||||
cy.seedPremium();
|
||||
cy.seedQueries();
|
||||
cy.viewport(1200, 660);
|
||||
});
|
||||
after(() => {
|
||||
cy.logout();
|
||||
});
|
||||
describe("Teams settings page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/settings/teams");
|
||||
});
|
||||
it("edits name of an existing team", () => {
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.contains("Apples");
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getAttached(".Select-arrow-zone").click();
|
||||
cy.findByText(/edit/i).click({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.getAttached(".edit-team-modal").within(() => {
|
||||
cy.findByLabelText(/team name/i)
|
||||
.clear()
|
||||
.type("Bananas");
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
});
|
||||
cy.findByText(/updated team name/i).should("be.visible");
|
||||
cy.findByText(/apples/i).should("not.exist");
|
||||
});
|
||||
it("deletes an existing team", () => {
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.contains("Bananas");
|
||||
cy.getAttached("tbody").within(() => {
|
||||
cy.getAttached("tr")
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.getAttached(".Select-arrow-zone").click();
|
||||
cy.findByText(/delete/i).click({ force: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.getAttached(".delete-team-modal .modal-cta-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /delete/i }).click();
|
||||
});
|
||||
cy.findByText(/successfully deleted/i).should("be.visible");
|
||||
cy.findByText(/bananas/i).should("not.exist");
|
||||
});
|
||||
});
|
||||
describe("Manage schedules page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
manageSchedulePage.visitManageSchedulePage();
|
||||
});
|
||||
it("adds a query to team schedule", () => {
|
||||
manageSchedulePage.changesTeam("All teams", "Oranges");
|
||||
manageSchedulePage.allowsAddSchedule();
|
||||
manageSchedulePage.verifiesAddedSchedule();
|
||||
});
|
||||
});
|
||||
describe("Team details page", () => {
|
||||
beforeEach(() => {
|
||||
cy.loginWithCySession();
|
||||
cy.visit("/settings/teams");
|
||||
cy.getAttached(".table-container").within(() => {
|
||||
cy.contains("Oranges").click({ force: true });
|
||||
});
|
||||
});
|
||||
it("allows to add new enroll secret to team", () => {
|
||||
cy.getAttached(".team-details__action-buttons--secondary-buttons")
|
||||
.contains("button", /manage enroll secret/i)
|
||||
.click();
|
||||
cy.getAttached(".enroll-secret-modal__add-secret")
|
||||
.contains("button", /add secret/i)
|
||||
.click();
|
||||
cy.getAttached(".secret-editor-modal .modal-cta-wrap")
|
||||
.contains("button", /save/i)
|
||||
.click();
|
||||
cy.getAttached(".enroll-secret-modal .modal-cta-wrap")
|
||||
.contains("button", /done/i)
|
||||
.click();
|
||||
});
|
||||
it("allows to see and click 'Add hosts'", () => {
|
||||
cy.getAttached(".team-details__action-buttons--primary")
|
||||
.contains("button", /add hosts/i)
|
||||
.click();
|
||||
cy.getAttached(".modal__content").contains("button", /done/i).click();
|
||||
});
|
||||
it("edits agent options of an existing team", () => {
|
||||
cy.findByText(/agent options/i).click();
|
||||
cy.contains(".ace_content", "config:");
|
||||
cy.getAttached(".ace_text-input")
|
||||
.first()
|
||||
.focus()
|
||||
.type("{selectall}{backspace}config:\n options:");
|
||||
|
||||
cy.findByRole("button", { name: /save options/i }).click();
|
||||
|
||||
cy.contains("span", /successfully updated/i).should("exist");
|
||||
cy.visit("/settings/teams/2/options");
|
||||
|
||||
cy.contains(/config:/i).should("be.visible");
|
||||
cy.contains(/options:/i).should("be.visible");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
const AppSettingsPage = {
|
||||
visitAgentOptions: () => {
|
||||
cy.visit("/settings/organization/agents");
|
||||
},
|
||||
|
||||
editAgentOptionsForm: (text: string) => {
|
||||
cy.findByRole("textbox").type(text, { force: true });
|
||||
cy.findByRole("button", { name: /save/i }).should("be.enabled").click();
|
||||
},
|
||||
};
|
||||
|
||||
export default AppSettingsPage;
|
@ -1,12 +0,0 @@
|
||||
const TeamSettingsPage = {
|
||||
visitTeamAgentOptions: (id: number) => {
|
||||
cy.visit(`settings/teams/${id}/options`);
|
||||
},
|
||||
|
||||
editAgentOptionsForm: (text: string) => {
|
||||
cy.findByRole("textbox").type(text, { force: true });
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
},
|
||||
};
|
||||
|
||||
export default TeamSettingsPage;
|
@ -1,21 +0,0 @@
|
||||
// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = () => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
};
|
@ -1,489 +0,0 @@
|
||||
import "@testing-library/cypress/add-commands";
|
||||
import "cypress-wait-until";
|
||||
import CONSTANTS from "./constants";
|
||||
|
||||
const { GOOD_PASSWORD } = CONSTANTS;
|
||||
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
||||
const SHELL = Cypress.platform === "win32" ? "cmd" : "bash";
|
||||
|
||||
Cypress.Commands.add("setup", () => {
|
||||
cy.exec("make e2e-reset-db e2e-setup", {
|
||||
timeout: 20000,
|
||||
env: { SHELL },
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("setupWithSoftware", () => {
|
||||
cy.exec("make e2e-reset-db e2e-setup-with-software", {
|
||||
timeout: 20000,
|
||||
env: { SHELL },
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("login", (email, password) => {
|
||||
email ||= "admin@example.com";
|
||||
password ||= GOOD_PASSWORD;
|
||||
cy.request("POST", "/api/latest/fleet/login", { email, password }).then(
|
||||
(resp) => {
|
||||
window.localStorage.setItem("FLEET::auth_token", resp.body.token);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("loginWithCySession", (email, password) => {
|
||||
email ||= "admin@example.com";
|
||||
password ||= GOOD_PASSWORD;
|
||||
cy.session([email, password], () => {
|
||||
cy.request("POST", "/api/latest/fleet/login", { email, password }).then(
|
||||
(resp) => {
|
||||
window.localStorage.setItem("FLEET::auth_token", resp.body.token);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("logout", () => {
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/logout",
|
||||
method: "POST",
|
||||
body: {},
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
}).then(() => {
|
||||
window.localStorage.removeItem("FLEET::auth_token");
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("setDesktopToken", (hostId, token) => {
|
||||
cy.exec(`make e2e-set-desktop-token host_id=${hostId} token=${token}`, {
|
||||
timeout: 20000,
|
||||
env: { SHELL },
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedQueries", () => {
|
||||
const queries = [
|
||||
{
|
||||
name: "Detect presence of authorized SSH keys",
|
||||
query:
|
||||
"SELECT username, authorized_keys. * FROM users CROSS JOIN authorized_keys USING (uid)",
|
||||
description:
|
||||
"Presence of authorized SSH keys may be unusual on laptops. Could be completely normal on servers, but may be worth auditing for unusual keys and/or changes.",
|
||||
observer_can_run: true,
|
||||
},
|
||||
{
|
||||
name: "Get authorized keys for Domain Joined Accounts",
|
||||
query:
|
||||
"SELECT * FROM users CROSS JOIN authorized_keys USING(uid) WHERE username IN (SELECT distinct(username) FROM last);",
|
||||
description: "List authorized_keys for each user on the system.",
|
||||
observer_can_run: false,
|
||||
},
|
||||
{
|
||||
name: "Get local user accounts",
|
||||
query:
|
||||
"SELECT uid, gid, username, description,directory, shell FROM users;",
|
||||
description:
|
||||
"Local user accounts (including domain accounts that have logged on locally (Windows)).",
|
||||
observer_can_run: false,
|
||||
},
|
||||
];
|
||||
|
||||
queries.forEach((queryForm) => {
|
||||
const { name, query, description, observer_can_run } = queryForm;
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/queries",
|
||||
method: "POST",
|
||||
body: { name, query, description, observer_can_run },
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedSchedule", () => {
|
||||
const scheduledQueries = [
|
||||
{
|
||||
interval: 86400,
|
||||
platform: "",
|
||||
query_id: 1,
|
||||
removed: false,
|
||||
shard: null,
|
||||
snapshot: true,
|
||||
version: "",
|
||||
},
|
||||
{
|
||||
interval: 604800,
|
||||
platform: "linux",
|
||||
query_id: 2,
|
||||
removed: true,
|
||||
shard: 50,
|
||||
snapshot: false,
|
||||
version: "4.6.0",
|
||||
},
|
||||
];
|
||||
|
||||
scheduledQueries.forEach((scheduleForm) => {
|
||||
const {
|
||||
interval,
|
||||
platform,
|
||||
query_id,
|
||||
removed,
|
||||
shard,
|
||||
snapshot,
|
||||
version,
|
||||
} = scheduleForm;
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/schedule",
|
||||
method: "POST",
|
||||
body: { interval, platform, query_id, removed, shard, snapshot, version },
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
Cypress.Commands.add("seedPacks", () => {
|
||||
const packs = [
|
||||
{
|
||||
name: "Mac starter pack",
|
||||
description: "Run all queries weekly on Mac hosts",
|
||||
},
|
||||
{
|
||||
name: "Windows starter pack",
|
||||
description: "Run all queries weekly on Windows hosts",
|
||||
},
|
||||
];
|
||||
|
||||
packs.forEach((packForm) => {
|
||||
const { name, description } = packForm;
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/packs",
|
||||
method: "POST",
|
||||
body: { name, description, host_ids: [], label_ids: [], team_ids: [] },
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedPolicies", (team = "") => {
|
||||
const policies = [
|
||||
{
|
||||
name: "Is Filevault enabled on macOS devices?",
|
||||
query:
|
||||
"SELECT 1 FROM disk_encryption WHERE user_uuid IS NOT '' AND filevault_status = 'on' LIMIT 1",
|
||||
description:
|
||||
"Checks to make sure that the Filevault feature is enabled on macOS devices.",
|
||||
resolution:
|
||||
"Choose Apple menu > System Preferences, then click Security & Privacy. Click the FileVault tab. Click the Lock icon, then enter an administrator name and password. Click Turn On FileVault.",
|
||||
platform: "darwin,linux",
|
||||
},
|
||||
{
|
||||
name: "Is Ubuntu, version 20.4.0 installed?",
|
||||
query:
|
||||
"SELECT 1 from os_version WHERE name = 'Ubuntu' AND major || '.' || minor || '.' || patch = '20.4.0';",
|
||||
description:
|
||||
"Returns yes or no for detecting operating system and version",
|
||||
resolution: "Update OS if needed",
|
||||
platform: "darwin,windows,linux",
|
||||
},
|
||||
{
|
||||
name: "Is Ubuntu, version 16.4.0 or later, installed?",
|
||||
query:
|
||||
"SELECT 1 from os_version WHERE name = 'Ubuntu' AND major || '.' || minor || '.' || patch >= '16.4.0';",
|
||||
description:
|
||||
"Returns yes or no for detecting operating system and version",
|
||||
resolution: "Update OS if needed",
|
||||
platform: "",
|
||||
},
|
||||
];
|
||||
|
||||
if (team === "apples") {
|
||||
policies.forEach((policyForm) => {
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/teams/1/policies",
|
||||
method: "POST",
|
||||
body: { ...policyForm },
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
policies.forEach((policyForm) => {
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/policies",
|
||||
method: "POST",
|
||||
body: { ...policyForm },
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add("setupSMTP", () => {
|
||||
const body = {
|
||||
smtp_settings: {
|
||||
authentication_type: "authtype_none",
|
||||
enable_smtp: true,
|
||||
port: 1025,
|
||||
sender_address: "fleet@example.com",
|
||||
server: "localhost",
|
||||
},
|
||||
};
|
||||
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/config",
|
||||
method: "PATCH",
|
||||
body,
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("setupSSO", (options) => {
|
||||
const body = {
|
||||
sso_settings: Object.assign(
|
||||
{},
|
||||
{
|
||||
enable_sso: true,
|
||||
enable_sso_idp_login: false,
|
||||
enable_jit_provisioning: false,
|
||||
entity_id: "https://localhost:8080",
|
||||
idp_name: "SimpleSAML",
|
||||
issuer_uri: "http://localhost:8080/simplesaml/saml2/idp/SSOService.php",
|
||||
metadata_url: "http://localhost:9080/simplesaml/saml2/idp/metadata.php",
|
||||
},
|
||||
options
|
||||
),
|
||||
};
|
||||
|
||||
cy.request({
|
||||
url: "/api/latest/fleet/config",
|
||||
method: "PATCH",
|
||||
body,
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
"loginSSO",
|
||||
({ username = "sso_user", password = "user123#" } = {}) => {
|
||||
// Note these requests set cookies that are required for the SSO flow to
|
||||
// work properly. This is handled automatically by the browser.
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url:
|
||||
"http://localhost:9080/simplesaml/saml2/idp/SSOService.php?spentityid=https://localhost:8080",
|
||||
followRedirect: false,
|
||||
}).then((firstResponse) => {
|
||||
const redirect = firstResponse.headers.location as string;
|
||||
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: redirect,
|
||||
followRedirect: false,
|
||||
}).then((secondResponse) => {
|
||||
const el = document.createElement("html");
|
||||
el.innerHTML = secondResponse.body;
|
||||
const authState = el
|
||||
.getElementsByTagName("input")
|
||||
.namedItem("AuthState").defaultValue;
|
||||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: redirect,
|
||||
body: `username=${username}&password=${password}&AuthState=${authState}`,
|
||||
form: true,
|
||||
followRedirect: false,
|
||||
}).then((finalResponse) => {
|
||||
el.innerHTML = finalResponse.body;
|
||||
const saml = el
|
||||
.getElementsByTagName("input")
|
||||
.namedItem("SAMLResponse").defaultValue;
|
||||
|
||||
// Load the callback URL with the response from the IdP
|
||||
cy.visit({
|
||||
url: "/api/v1/fleet/sso/callback",
|
||||
method: "POST",
|
||||
body: {
|
||||
SAMLResponse: saml,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.Commands.add("getEmails", () => {
|
||||
return cy
|
||||
.request("http://localhost:8025/api/v2/messages")
|
||||
.then((response) => {
|
||||
expect(response.status).to.eq(200);
|
||||
return response;
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedFree", () => {
|
||||
const authToken = window.localStorage.getItem("FLEET::auth_token");
|
||||
cy.exec("bash ./tools/api/fleet/teams/create_free", {
|
||||
env: {
|
||||
TOKEN: authToken,
|
||||
CURL_FLAGS: "-k",
|
||||
SERVER_URL: Cypress.config().baseUrl,
|
||||
// clear any value for FLEET_ENV_PATH since we set the environment explicitly just above
|
||||
FLEET_ENV_PATH: "",
|
||||
SHELL,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedPremium", () => {
|
||||
const authToken = window.localStorage.getItem("FLEET::auth_token");
|
||||
cy.exec("bash ./tools/api/fleet/teams/create_premium", {
|
||||
env: {
|
||||
TOKEN: authToken,
|
||||
CURL_FLAGS: "-k",
|
||||
SERVER_URL: Cypress.config().baseUrl,
|
||||
// clear any value for FLEET_ENV_PATH since we set the environment explicitly just above
|
||||
FLEET_ENV_PATH: "",
|
||||
SHELL,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedFigma", () => {
|
||||
const authToken = window.localStorage.getItem("FLEET::auth_token");
|
||||
cy.exec("bash ./tools/api/fleet/teams/create_figma", {
|
||||
env: {
|
||||
TOKEN: authToken,
|
||||
CURL_FLAGS: "-k",
|
||||
SERVER_URL: Cypress.config().baseUrl,
|
||||
// clear any value for FLEET_ENV_PATH since we set the environment explicitly just above
|
||||
FLEET_ENV_PATH: "",
|
||||
SHELL,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("addUser", (options = {}) => {
|
||||
let { password, email, globalRole } = options;
|
||||
password ||= GOOD_PASSWORD;
|
||||
email ||= `admin@example.com`;
|
||||
globalRole ||= "admin";
|
||||
|
||||
cy.exec(
|
||||
`./build/fleetctl user create --context e2e --password "${password}" --email "${email}" --global-role "${globalRole}"`,
|
||||
{
|
||||
timeout: 5000,
|
||||
env: { SHELL },
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Ability to add a docker host to a team using args if ran after seedPremium()
|
||||
Cypress.Commands.add("addDockerHost", (team = "") => {
|
||||
const serverPort = new URL(Cypress.config().baseUrl).port;
|
||||
// Get enroll secret
|
||||
let enrollSecretUrl = "/api/latest/fleet/spec/enroll_secret";
|
||||
if (team === "apples") {
|
||||
enrollSecretUrl = "/api/latest/fleet/teams/1/secrets";
|
||||
} else if (team === "oranges") {
|
||||
enrollSecretUrl = "/api/latest/fleet/teams/2/secrets";
|
||||
}
|
||||
|
||||
cy.request({
|
||||
url: enrollSecretUrl,
|
||||
auth: {
|
||||
bearer: window.localStorage.getItem("FLEET::auth_token"),
|
||||
},
|
||||
}).then(({ body }) => {
|
||||
const enrollSecret =
|
||||
team === "" ? body.spec.secrets[0].secret : body.secrets[0].secret;
|
||||
|
||||
// Start up docker-compose with enroll secret
|
||||
cy.exec(
|
||||
"docker-compose -f tools/osquery/docker-compose.yml up -d ubuntu20-osquery",
|
||||
{
|
||||
env: {
|
||||
ENROLL_SECRET: enrollSecret,
|
||||
FLEET_SERVER: `host.docker.internal:${serverPort}`,
|
||||
SHELL,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("stopDockerHost", () => {
|
||||
// Start up docker-compose with enroll secret
|
||||
cy.exec("docker-compose -f tools/osquery/docker-compose.yml stop", {
|
||||
env: {
|
||||
// Not that ENROLL_SECRET must be specified or docker-compose errors,
|
||||
// even when just trying to shut down the hosts.
|
||||
ENROLL_SECRET: "invalid",
|
||||
SHELL,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("clearDownloads", () => {
|
||||
// windows has issue with downloads location
|
||||
if (Cypress.platform !== "win32") {
|
||||
cy.exec(`rm -rf ${Cypress.config("downloadsFolder")}`, { env: { SHELL } });
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add("getAttached", (selector) => {
|
||||
const uniqueAlias = `element_${selector}`;
|
||||
|
||||
return cy
|
||||
.waitUntil(
|
||||
() =>
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy
|
||||
.get(selector)
|
||||
.as(uniqueAlias)
|
||||
.wait(1)
|
||||
.then(($el) => Cypress.dom.isAttached($el)),
|
||||
{ timeout: 10000, interval: 10 }
|
||||
)
|
||||
.get(`@${uniqueAlias}`);
|
||||
});
|
@ -1,245 +0,0 @@
|
||||
const GOOD_PASSWORD = "password123#";
|
||||
const BAD_PASSWORD_LENGTH = "password12#";
|
||||
const BAD_PASSWORD_NO_NUMBER = "password####";
|
||||
const BAD_PASSWORD_NO_SYMBOL = "password1234";
|
||||
const CONFIG_INTEGRATIONS_AUTOMATIONS = {
|
||||
org_info: {
|
||||
org_name: "Fleet Test",
|
||||
org_logo_url: "",
|
||||
},
|
||||
server_settings: {
|
||||
server_url: "https://localhost:8642",
|
||||
live_query_disabled: false,
|
||||
enable_analytics: true,
|
||||
deferred_save_host: false,
|
||||
},
|
||||
smtp_settings: {
|
||||
enable_smtp: false,
|
||||
configured: false,
|
||||
sender_address: "",
|
||||
server: "",
|
||||
port: 587,
|
||||
authentication_type: "authtype_username_password",
|
||||
user_name: "",
|
||||
password: "",
|
||||
enable_ssl_tls: true,
|
||||
authentication_method: "authmethod_plain",
|
||||
domain: "",
|
||||
verify_ssl_certs: true,
|
||||
enable_start_tls: true,
|
||||
},
|
||||
host_expiry_settings: {
|
||||
host_expiry_enabled: true,
|
||||
host_expiry_window: 9,
|
||||
},
|
||||
features: {
|
||||
enable_host_users: true,
|
||||
enable_software_inventory: true,
|
||||
},
|
||||
agent_options: {
|
||||
config: {
|
||||
options: {
|
||||
pack_delimiter: "/",
|
||||
logger_tls_period: 10,
|
||||
distributed_plugin: "tls",
|
||||
disable_distributed: false,
|
||||
logger_tls_endpoint: "/api/osquery/log",
|
||||
distributed_interval: 10,
|
||||
distributed_tls_max_attempts: 3,
|
||||
},
|
||||
decorators: {
|
||||
load: [
|
||||
"SELECT uuid AS host_uuid FROM system_info;",
|
||||
"SELECT hostname AS hostname FROM system_info;",
|
||||
],
|
||||
},
|
||||
},
|
||||
overrides: {},
|
||||
},
|
||||
sso_settings: {
|
||||
entity_id: "",
|
||||
issuer_uri: "",
|
||||
idp_image_url: "",
|
||||
metadata: "",
|
||||
metadata_url: "",
|
||||
idp_name: "",
|
||||
enable_sso: false,
|
||||
enable_sso_idp_login: false,
|
||||
enable_jit_provisioning: false,
|
||||
},
|
||||
vulnerability_settings: {
|
||||
databases_path: "",
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
enable_vulnerabilities_webhook: false,
|
||||
destination_url: "",
|
||||
host_batch_size: 0,
|
||||
},
|
||||
interval: "24h0m0s",
|
||||
},
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: true,
|
||||
enable_software_vulnerabilities: true,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
update_interval: {
|
||||
osquery_detail: 3600000000000,
|
||||
osquery_policy: 3600000000000,
|
||||
},
|
||||
vulnerabilities: {
|
||||
databases_path: "/tmp/vulndbs",
|
||||
periodicity: 3600000000000,
|
||||
cpe_database_url: "",
|
||||
cve_feed_prefix_url: "",
|
||||
current_instance_checks: "auto",
|
||||
disable_data_sync: false,
|
||||
recent_vulnerability_max_age: 2592000000000000,
|
||||
},
|
||||
license: {
|
||||
tier: "premium",
|
||||
organization: "development-only",
|
||||
device_count: 100,
|
||||
expiration: "2099-06-30T20:00:00-04:00",
|
||||
note: "for development only",
|
||||
},
|
||||
logging: {
|
||||
debug: false,
|
||||
json: false,
|
||||
result: {
|
||||
plugin: "filesystem",
|
||||
config: {
|
||||
status_log_file:
|
||||
"/var/folders/xh/bxm1d2615tv3vrg4zrxq540h0000gn/T/osquery_status",
|
||||
result_log_file:
|
||||
"/var/folders/xh/bxm1d2615tv3vrg4zrxq540h0000gn/T/osquery_result",
|
||||
enable_log_rotation: false,
|
||||
enable_log_compression: false,
|
||||
},
|
||||
},
|
||||
status: {
|
||||
plugin: "filesystem",
|
||||
config: {
|
||||
status_log_file:
|
||||
"/var/folders/xh/bxm1d2615tv3vrg4zrxq540h0000gn/T/osquery_status",
|
||||
result_log_file:
|
||||
"/var/folders/xh/bxm1d2615tv3vrg4zrxq540h0000gn/T/osquery_result",
|
||||
enable_log_rotation: false,
|
||||
enable_log_compression: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED = {
|
||||
...CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
integrations: {
|
||||
jira: [
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira1@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 1",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.atlassian.com",
|
||||
username: "jira2@example.com",
|
||||
api_token: "jira123",
|
||||
project_key: "PROJECT 2",
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
zendesk: [
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk1@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 12345678,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
{
|
||||
url: "https://fleetdm.zendesk.com",
|
||||
email: "zendesk2@example.com",
|
||||
api_token: "zendesk123",
|
||||
group_id: 87654321,
|
||||
enable_failing_policies: false,
|
||||
enable_software_vulnerabilities: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
webhook_settings: {
|
||||
host_status_webhook: {
|
||||
enable_host_status_webhook: false,
|
||||
destination_url: "",
|
||||
host_percentage: 0,
|
||||
days_count: 0,
|
||||
},
|
||||
failing_policies_webhook: {
|
||||
enable_failing_policies_webhook: false,
|
||||
destination_url: "https://www.foo.com/bar",
|
||||
policy_ids: [5, 10],
|
||||
host_batch_size: 0,
|
||||
},
|
||||
vulnerabilities_webhook: {
|
||||
destination_url: "http://www.foo.com/bar",
|
||||
enable_vulnerabilities_webhook: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
GOOD_PASSWORD,
|
||||
BAD_PASSWORD_LENGTH,
|
||||
BAD_PASSWORD_NO_NUMBER,
|
||||
BAD_PASSWORD_NO_SYMBOL,
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS,
|
||||
CONFIG_INTEGRATIONS_AUTOMATIONS_DISABLED,
|
||||
};
|
140
cypress/support/index.d.ts
vendored
140
cypress/support/index.d.ts
vendored
@ -1,140 +0,0 @@
|
||||
// load type definitions that come with Cypress module
|
||||
// <reference types="cypress" />
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Custom command to setup the testing environment.
|
||||
*/
|
||||
setup(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to setup the testing environment with fixture data for software and vulnerabilities.
|
||||
*/
|
||||
setupWithSoftware(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to login the user programmatically using the fleet API.
|
||||
*/
|
||||
login(email?: string, password?: string): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to login the user programmatically using the fleet API
|
||||
* but with a Cypress session wrapper.
|
||||
*/
|
||||
loginWithCySession(email?: string, password?: string): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to log out the current user.
|
||||
*/
|
||||
logout(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to set a Fleet Desktop token to a host.
|
||||
*/
|
||||
setDesktopToken(hostId?: number, token?: string): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to add new queries by default.
|
||||
*/
|
||||
seedQueries(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to add new scheduled queries by default.
|
||||
*/
|
||||
seedSchedule(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to add new policies by default.
|
||||
*/
|
||||
seedPolicies(teamName?: string): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to add a new user in Fleet (via fleetctl).
|
||||
*/
|
||||
addUser(options?: {
|
||||
email?: string;
|
||||
password?: string;
|
||||
globalRole?: string;
|
||||
}): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to setup the SMTP configuration for this testing environment.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
setupSMTP(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to set up SSO auth with the local server.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
setupSSO(options?: {
|
||||
enable_sso_idp_login?: boolean;
|
||||
enable_jit_provisioning?: boolean;
|
||||
}): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to login a user1@example.com via SSO.
|
||||
*/
|
||||
loginSSO(options?: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
}): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to get the emails handled by the Mailhog server.
|
||||
*/
|
||||
getEmails(): Chainable;
|
||||
|
||||
/**
|
||||
* Custom command to seed the Free tier teams/users.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
seedFree(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to seed the Premium tier teams/users.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
seedPremium(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to seed the teams/users as represented in Figma.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
seedFigma(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to add Docker osquery host.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
addDockerHost(teamName?: string): Chainable;
|
||||
|
||||
/**
|
||||
* Custom command to stop any running Docker hosts.
|
||||
*/
|
||||
stopDockerHost(): Chainable;
|
||||
|
||||
/**
|
||||
* Custom command to clear downloaded files from test machine.
|
||||
*/
|
||||
clearDownloads(): Chainable;
|
||||
|
||||
/**
|
||||
* Custom command to get any element describe only if it is attached to the DOM.
|
||||
*/
|
||||
getAttached(selector: string): Chainable;
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import "./commands";
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": [
|
||||
"cypress",
|
||||
"@testing-library/cypress",
|
||||
"node",
|
||||
"cypress-wait-until"
|
||||
]
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
15
package.json
15
package.json
@ -4,16 +4,10 @@
|
||||
"description": "The premier osquery fleet manager.",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint frontend cypress --ext .js,.jsx,.ts,.tsx",
|
||||
"prettier:check": "prettier --check frontend/**/*.{jsx,js,tsx,ts} ./cypress/**/*.{js,ts}",
|
||||
"lint": "eslint frontend --ext .js,.jsx,.ts,.tsx",
|
||||
"prettier:check": "prettier --check frontend/**/*.{jsx,js,tsx,ts}",
|
||||
"test": "jest --config ./frontend/test/jest.config.ts",
|
||||
"test:ci": "jest --config ./frontend/test/jest.config.ts --ci --coverage",
|
||||
"e2e-browser": "cypress open",
|
||||
"e2e-browser:free": "yarn cypress open --config-file cypress/cypress-free.json",
|
||||
"e2e-browser:premium": "yarn cypress open --config-file cypress/cypress-premium.json",
|
||||
"e2e-cli": "cypress run",
|
||||
"e2e-cli:free": "yarn cypress run --config-file cypress/cypress-free.json",
|
||||
"e2e-cli:premium": "yarn cypress run --config-file cypress/cypress-premium.json",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
@ -90,14 +84,12 @@
|
||||
"@storybook/addon-mdx-gfm": "7.0.7",
|
||||
"@storybook/react": "7.0.7",
|
||||
"@storybook/react-webpack5": "7.0.7",
|
||||
"@testing-library/cypress": "8.0.2",
|
||||
"@testing-library/jest-dom": "5.16.2",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@tsconfig/recommended": "1.0.1",
|
||||
"@types/chrome": "0.0.237",
|
||||
"@types/classnames": "0.0.32",
|
||||
"@types/cypress": "1.1.3",
|
||||
"@types/expect": "1.20.3",
|
||||
"@types/file-saver": "2.0.5",
|
||||
"@types/js-md5": "0.4.3",
|
||||
@ -126,14 +118,11 @@
|
||||
"bourbon": "5.1.0",
|
||||
"classnames": "2.2.5",
|
||||
"css-loader": "6.7.3",
|
||||
"cypress": "9.5.1",
|
||||
"cypress-wait-until": "1.7.2",
|
||||
"esbuild-loader": "2.18.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-airbnb": "15.1.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-import-resolver-webpack": "0.10.0",
|
||||
"eslint-plugin-cypress": "2.12.1",
|
||||
"eslint-plugin-import": "2.25.4",
|
||||
"eslint-plugin-jest": "20.0.3",
|
||||
"eslint-plugin-jsx-a11y": "5.1.1",
|
||||
|
Loading…
Reference in New Issue
Block a user