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:
Zach Wasserman 2021-06-09 11:56:59 -07:00 committed by GitHub
parent 588a48dd67
commit 8c97b36764
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 328 additions and 25 deletions

View file

@ -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

View file

@ -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', () => {

View file

@ -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]);
});
});
});

View file

@ -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();

View file

@ -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

View 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!
});
});
}

View 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!
});
});
}

View 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!
});
});
}

View 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!
});
});
}

View 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
}
```

View 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 });
});
});
}

View 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!
});
});
}

View 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!
});
});
}

View file

@ -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 }
);
});

View file

@ -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>;
}
}

View file

@ -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
View file

3
tools/saml/README.md Normal file
View 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
View 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',
),
),
);