mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Set up Cypress testing for Teams/Tiers (#1005)
- Update names/roles of users in `make e2e-setup`. - Update test SSO user info. - Add Cypress commands for seeding users/Teams. - Stub Cypress tests for team/tier matrix.
This commit is contained in:
parent
588a48dd67
commit
8c97b36764
19 changed files with 328 additions and 25 deletions
11
Makefile
11
Makefile
|
|
@ -212,12 +212,11 @@ e2e-reset-db:
|
|||
./build/fleet prepare db --mysql_address=localhost:3307 --mysql_username=root --mysql_password=toor --mysql_database=e2e
|
||||
|
||||
e2e-setup:
|
||||
./build/fleetctl config set --context e2e --address https://localhost:8642
|
||||
./build/fleetctl config set --context e2e --tls-skip-verify true
|
||||
./build/fleetctl setup --context e2e --email=test@example.com --username=test --password=admin123# --org-name='Fleet Test'
|
||||
./build/fleetctl user create --context e2e --username=user1 --email=user1@example.com --sso=true
|
||||
./build/fleetctl user create --context e2e --email=test+1@example.com --username=test1 --password=admin123#
|
||||
./build/fleetctl user create --context e2e --email=test+2@example.com --username=test2 --password=admin123#
|
||||
./build/fleetctl config set --context e2e --address https://localhost:8642 --tls-skip-verify true
|
||||
./build/fleetctl setup --context e2e --email=admin@example.com --username=admin --password=user123# --org-name='Fleet Test'
|
||||
./build/fleetctl user create --context e2e --email=maintainer@example.com --username=maintainer --password=user123# --global-role=maintainer
|
||||
./build/fleetctl user create --context e2e --email=observer@example.com --username=observer --password=user123# --global-role=observer
|
||||
./build/fleetctl user create --context e2e --username=sso_user --email=sso_user@example.com --sso=true
|
||||
|
||||
e2e-serve-core:
|
||||
./build/fleet serve --mysql_address=localhost:3307 --mysql_username=root --mysql_password=toor --mysql_database=e2e --server_address=localhost:8642
|
||||
|
|
|
|||
|
|
@ -16,17 +16,19 @@ describe("Manage Users", () => {
|
|||
|
||||
cy.wait("@getUsers");
|
||||
|
||||
cy.findByText("test@example.com").should("exist");
|
||||
cy.findByText("test+1@example.com").should("exist");
|
||||
cy.findByText("test+2@example.com").should("exist");
|
||||
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("test@example.com");
|
||||
cy.findByPlaceholderText("Search").type("admin");
|
||||
|
||||
cy.wait("@getUsers");
|
||||
|
||||
cy.findByText("test@example.com").should("exist");
|
||||
cy.findByText("test+1@example.com").should("not.exist");
|
||||
cy.findByText("test+2@example.com").should("not.exist");
|
||||
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('Creating a user', () => {
|
||||
|
|
|
|||
|
|
@ -139,14 +139,13 @@ describe("Settings flow", () => {
|
|||
|
||||
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("test");
|
||||
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"
|
||||
);
|
||||
console.log(response.body.items[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ describe("Sessions", () => {
|
|||
cy.contains(/forgot password/i);
|
||||
|
||||
// Log in
|
||||
cy.get("input").first().type("test@example.com");
|
||||
cy.get("input").last().type("admin123#");
|
||||
cy.get("input").first().type("admin@example.com");
|
||||
cy.get("input").last().type("user123#");
|
||||
cy.get("button").click();
|
||||
|
||||
// Verify dashboard
|
||||
|
|
@ -27,7 +27,7 @@ describe("Sessions", () => {
|
|||
|
||||
it("Fails login with invalid password", () => {
|
||||
cy.visit("/");
|
||||
cy.get("input").first().type("test@example.com");
|
||||
cy.get("input").first().type("admin@example.com");
|
||||
cy.get("input").last().type("bad_password");
|
||||
cy.get(".button").click();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ describe("SSO Sessions", () => {
|
|||
cy.setup();
|
||||
});
|
||||
|
||||
it("Can login with username/password", () => {
|
||||
it("Non-SSO user can login with username/password", () => {
|
||||
cy.login();
|
||||
cy.setupSSO((enable_idp_login = true));
|
||||
cy.logout();
|
||||
|
|
@ -12,8 +12,8 @@ describe("SSO Sessions", () => {
|
|||
cy.contains(/forgot password/i);
|
||||
|
||||
// Log in
|
||||
cy.get("input").first().type("test@example.com");
|
||||
cy.get("input").last().type("admin123#");
|
||||
cy.get("input").first().type("admin@example.com");
|
||||
cy.get("input").last().type("user123#");
|
||||
cy.contains("button", "Login").click();
|
||||
|
||||
// Verify dashboard
|
||||
|
|
|
|||
20
cypress/integration/basic/admin.spec.ts
Normal file
20
cypress/integration/basic/admin.spec.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
if (Cypress.env("FLEET_TIER") === "basic") {
|
||||
describe("Basic tier - Admin user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedBasic();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("anna@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// TODO write the test!
|
||||
});
|
||||
});
|
||||
}
|
||||
20
cypress/integration/basic/maintainer.spec.ts
Normal file
20
cypress/integration/basic/maintainer.spec.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
if (Cypress.env("FLEET_TIER") === "basic") {
|
||||
describe("Basic tier - Maintainer user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedBasic();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("mary@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// TODO write the test!
|
||||
});
|
||||
});
|
||||
}
|
||||
20
cypress/integration/basic/observer.spec.ts
Normal file
20
cypress/integration/basic/observer.spec.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
if (Cypress.env("FLEET_TIER") === "basic") {
|
||||
describe("Basic tier - Observer user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedBasic();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("oliver@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// TODO write the test!
|
||||
});
|
||||
});
|
||||
}
|
||||
20
cypress/integration/basic/team_maintainer_observer.spec.ts
Normal file
20
cypress/integration/basic/team_maintainer_observer.spec.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
if (Cypress.env("FLEET_TIER") === "basic") {
|
||||
describe("Basic tier - Team observer/maintainer user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedBasic();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("marco@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// TODO write the test!
|
||||
});
|
||||
});
|
||||
}
|
||||
23
cypress/integration/core/README.md
Normal file
23
cypress/integration/core/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Core tier tests
|
||||
|
||||
These tests should only run when the server is in `core` tier.
|
||||
|
||||
To enable the tests:
|
||||
|
||||
```sh
|
||||
export CYPRESS_FLEET_TIER=core
|
||||
```
|
||||
|
||||
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") === "core") {
|
||||
// test suite here
|
||||
}
|
||||
```
|
||||
52
cypress/integration/core/admin.spec.ts
Normal file
52
cypress/integration/core/admin.spec.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
if (Cypress.env("FLEET_TIER") === "core") {
|
||||
describe("Core tier - Admin user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedCore();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("anna@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// "team" should not appear anywhere
|
||||
cy.contains(/team/i).should("not.exist");
|
||||
|
||||
// See and select "add new host"
|
||||
cy.findByRole("button", { name: /new host/i }).click();
|
||||
cy.contains(/team/i).should("not.exist");
|
||||
cy.findByRole("button", { name: /done/i }).click();
|
||||
|
||||
// See and select "add new label"
|
||||
cy.findByRole("button", { name: /new label/i }).click();
|
||||
cy.findByRole("button", { name: /cancel/i }).click();
|
||||
|
||||
// Query page
|
||||
cy.contains("a", "Queries").click();
|
||||
cy.contains(/observers can run/i);
|
||||
cy.findByRole("button", { name: /new query/i }).click();
|
||||
|
||||
// New query
|
||||
cy.findByLabelText(/query name/i)
|
||||
.click()
|
||||
.type("time");
|
||||
// ACE editor requires special handling to get typing to work sometimes
|
||||
cy.get(".ace_text-input")
|
||||
.first()
|
||||
.click({ force: true })
|
||||
.type("{selectall}{backspace}SELECT * FROM time;", { force: true });
|
||||
cy.findByLabelText(/description/i)
|
||||
.click()
|
||||
.type("Get the time.");
|
||||
cy.findByLabelText(/observers can run/i).click({ force: true });
|
||||
cy.findByRole("button", { name: /save/i }).click();
|
||||
cy.findByRole("button", { name: /new/i }).click();
|
||||
cy.contains("a", /back to queries/i).click({ force: true });
|
||||
});
|
||||
});
|
||||
}
|
||||
20
cypress/integration/core/maintainer.spec.ts
Normal file
20
cypress/integration/core/maintainer.spec.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
if (Cypress.env("FLEET_TIER") === "core") {
|
||||
describe("Core tier - Maintainer user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedCore();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("mary@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// TODO write the test!
|
||||
});
|
||||
});
|
||||
}
|
||||
20
cypress/integration/core/observer.spec.ts
Normal file
20
cypress/integration/core/observer.spec.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
if (Cypress.env("FLEET_TIER") === "core") {
|
||||
describe("Core tier - Observer user", () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.login();
|
||||
cy.seedCore();
|
||||
cy.logout();
|
||||
});
|
||||
|
||||
it("Can perform the appropriate actions", () => {
|
||||
cy.login("oliver@organization.com", "user123#");
|
||||
cy.visit("/");
|
||||
|
||||
// Ensure page is loaded
|
||||
cy.contains("All hosts");
|
||||
|
||||
// TODO write the test!
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ Cypress.Commands.add("setup", () => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("login", (username, password) => {
|
||||
username ||= "test";
|
||||
password ||= "admin123#";
|
||||
username ||= "admin";
|
||||
password ||= "user123#";
|
||||
cy.request("POST", "/api/v1/fleet/login", { username, password }).then(
|
||||
(resp) => {
|
||||
window.localStorage.setItem("FLEET::auth_token", resp.body.token);
|
||||
|
|
@ -120,7 +120,7 @@ Cypress.Commands.add("loginSSO", () => {
|
|||
cy.request({
|
||||
method: "POST",
|
||||
url: redirect,
|
||||
body: `username=user1&password=user1pass&AuthState=${authState}`,
|
||||
body: `username=sso_user&password=user123#&AuthState=${authState}`,
|
||||
form: true,
|
||||
followRedirect: false,
|
||||
}).then((finalResponse) => {
|
||||
|
|
@ -149,3 +149,54 @@ Cypress.Commands.add("getEmails", () => {
|
|||
return response;
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedCore", () => {
|
||||
const authToken = window.localStorage.getItem("FLEET::auth_token");
|
||||
cy.exec("bash ./tools/api/fleet/teams/create_core", {
|
||||
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: "",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("seedBasic", () => {
|
||||
const authToken = window.localStorage.getItem("FLEET::auth_token");
|
||||
cy.exec("bash ./tools/api/fleet/teams/create_basic", {
|
||||
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: "",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
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: "",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("addUser", (username, options = {}) => {
|
||||
let { password, email, globalRole } = options;
|
||||
password ||= "test123#";
|
||||
email ||= `${username}@example.com`;
|
||||
globalRole ||= "admin";
|
||||
|
||||
cy.exec(
|
||||
`./build/fleetctl user create --context e2e --username "${username}" --password "${password}" --email "${email}" --global-role "${globalRole}"`,
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
});
|
||||
|
|
|
|||
34
cypress/support/index.d.ts
vendored
34
cypress/support/index.d.ts
vendored
|
|
@ -11,13 +11,21 @@ declare namespace Cypress {
|
|||
/**
|
||||
* Custom command to login the user programmatically using the fleet API.
|
||||
*/
|
||||
login(): Chainable<Element>;
|
||||
login(username?: string, password?: string): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to log out the current user.
|
||||
*/
|
||||
logout(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to add a new user in Fleet (via fleetctl).
|
||||
*/
|
||||
addUser(
|
||||
username: string,
|
||||
options?: { username?: string; password?: string; globalRole?: string }
|
||||
): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to setup the SMTP configuration for this testing environment.
|
||||
*
|
||||
|
|
@ -43,5 +51,29 @@ declare namespace Cypress {
|
|||
* Custom command to get the emails handled by the Mailhog server.
|
||||
*/
|
||||
getEmails(): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Custom command to seed the Core tier teams/users.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
seedCore(): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to seed the Basic tier teams/users.
|
||||
*
|
||||
* NOTE: login() command is required before this, as it will make authenticated
|
||||
* requests.
|
||||
*/
|
||||
seedBasic(): 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>;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ services:
|
|||
environment:
|
||||
SIMPLESAMLPHP_SP_ENTITY_ID: 'https://localhost:8080'
|
||||
SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE: 'https://localhost:8080/api/v1/fleet/sso/callback'
|
||||
volumes:
|
||||
- ./tools/saml/users.php:/var/www/simplesamlphp/config/authsources.php
|
||||
ports:
|
||||
- "9080:8080"
|
||||
- "9443:8443"
|
||||
|
|
|
|||
0
tools/api/fleet/teams/create_core
Normal file → Executable file
0
tools/api/fleet/teams/create_core
Normal file → Executable file
3
tools/saml/README.md
Normal file
3
tools/saml/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
The [users.php](./users.php) file in this directory is mounted into the SimpleSAMLPHP Docker container to use for testing SSO with Fleet.
|
||||
|
||||
Edit that file to change the credentials or add new SSO users for local testing.
|
||||
20
tools/saml/users.php
Normal file
20
tools/saml/users.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
$config = array(
|
||||
|
||||
'admin' => array(
|
||||
'core:AdminPassword',
|
||||
),
|
||||
|
||||
'example-userpass' => array(
|
||||
'exampleauth:UserPass',
|
||||
// username: sso_user
|
||||
// password: user123#
|
||||
'sso_user:user123#' => array(
|
||||
'uid' => array('1'),
|
||||
'eduPersonAffiliation' => array('group1'),
|
||||
'email' => 'sso_user@example.com',
|
||||
),
|
||||
),
|
||||
|
||||
);
|
||||
Loading…
Reference in a new issue