mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-15 12:47:56 +08:00
create e2e test for auth buttons (#1907)
This PR adds a few helpful additions regarding authentication. Changes: * e2e tests are now run on test_oauth via a passed config.yaml * node dev server correctly handles `/login` and `/logout` endpoints to make developing for auth easier * Introduced auth e2e tests to check that buttons display and work
This commit is contained in:
committed by
GitHub
parent
b5ec43c4b1
commit
c4c48b9a57
@@ -3,6 +3,8 @@ include ../common.mk
|
||||
ANNOTATIONS := $(if $(ANNOTATIONS),$(ANNOTATIONS),../server/test/fixtures/pbmc3k-annotations.csv)
|
||||
ANNOTATIONS_FILENAME := $(shell basename $(ANNOTATIONS))
|
||||
|
||||
CXG_CONFIG := $(if $(CXG_CONFIG), $(CXG_CONFIG), ./__tests__/e2e/test_config.yaml)
|
||||
|
||||
# Packaging
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@@ -31,7 +33,7 @@ start-frontend:
|
||||
.PHONY: smoke-test
|
||||
smoke-test:
|
||||
start_server_and_test \
|
||||
'CXG_OPTIONS="--disable-annotations" $(MAKE) start-server' \
|
||||
'CXG_OPTIONS="--config-file $(CXG_CONFIG)" $(MAKE) start-server' \
|
||||
$(CXG_SERVER_PORT) \
|
||||
'CXG_URL_BASE="http://localhost:$(CXG_SERVER_PORT)" npm run e2e -- --verbose false'
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ export async function login() {
|
||||
|
||||
await goToPage(appUrlBase);
|
||||
|
||||
await clickOn("auth-button");
|
||||
await clickOn("log-in");
|
||||
|
||||
// (thuang): Auth0 form is unstable and unsafe for input until verified
|
||||
await waitUntilFormFieldStable('[name="email"]');
|
||||
@@ -341,16 +341,15 @@ export async function login() {
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
await clickOnUntil("menu", async () => {
|
||||
await expect(page).toMatch("Log Out");
|
||||
|
||||
await clickOnUntil("user-info", async () => {
|
||||
await waitByID("log-out");
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: "networkidle0" }),
|
||||
expect(page).toClick("a", { text: "Log Out" }),
|
||||
clickOn("log-out"),
|
||||
]);
|
||||
});
|
||||
|
||||
await expect(page).toMatch("Log In");
|
||||
await waitByID("log-in");
|
||||
}
|
||||
|
||||
async function waitUntilFormFieldStable(selector) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
goToPage,
|
||||
typeInto,
|
||||
waitByID,
|
||||
clickOnUntil,
|
||||
} from "./puppeteerUtils";
|
||||
|
||||
import {
|
||||
@@ -521,6 +522,17 @@ test("lasso moves after pan", async () => {
|
||||
expect(panCount).toBe(initialCount);
|
||||
});
|
||||
|
||||
describe("auth buttons", () => {
|
||||
test("login then logout", async () => {
|
||||
await goToPage(appUrlBase);
|
||||
await clickOnUntil("log-in", async () => {
|
||||
await page.waitForNavigation({ waitUntil: "networkidle0" });
|
||||
await waitByID("user-info");
|
||||
});
|
||||
await logout();
|
||||
});
|
||||
});
|
||||
|
||||
const conditionalDescribe =
|
||||
process.env.TEST_AUTH_INTEGRATION === "true" ? describe : describe.skip;
|
||||
|
||||
|
||||
47
client/__tests__/e2e/test_config.yaml
Normal file
47
client/__tests__/e2e/test_config.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
server:
|
||||
app:
|
||||
force_https: true
|
||||
|
||||
# By default, cellxgene will serve api requests from the same base url as the webpage.
|
||||
# In general api_base_url and web_base_url will not need to be set.
|
||||
# There are two reasons to set these parameters:
|
||||
# 1. Oauth authentication is used; the oauth server will redirect back to the api_base_url after login,
|
||||
# which then redirects back to the web_base_url. If the web_base_url is not set, it will default to
|
||||
# the api_base_url. If oauth authentication is used, the api_base_url must be set.
|
||||
# For a local test (where the server runs on "http://localhost:<port>"), then the api_base_url may be
|
||||
# set to the string "local".
|
||||
# 2. The cellxgene deploymnent is in an environment where the webpage and api have
|
||||
# different base urls. In this case both api_base_url and web_base_url must be set.
|
||||
# It is up to the server admin to ensure that the networking is setup correctly for this environment.
|
||||
api_base_url: http://localhost:5005
|
||||
web_base_url: http://localhost:3000
|
||||
|
||||
authentication:
|
||||
# The authentication types may be "none", "session", "oauth"
|
||||
# none: No authentication support, features like user_annotations must not be enabled.
|
||||
# session: A session based userid is automatically generated. (no params needed)
|
||||
# oauth: oauth2 is used for authentication; parameters are defined in params_oauth.
|
||||
type: test
|
||||
|
||||
dataset:
|
||||
app:
|
||||
about_legal_tos: null
|
||||
about_legal_privacy: null
|
||||
|
||||
presentation:
|
||||
max_categories: 1000
|
||||
custom_colors: true
|
||||
|
||||
user_annotations:
|
||||
enable: false
|
||||
type: local_file_csv
|
||||
local_file_csv:
|
||||
directory: null
|
||||
file: null
|
||||
ontology:
|
||||
enable: false
|
||||
obo_location: null
|
||||
|
||||
embeddings:
|
||||
names: []
|
||||
enable_reembedding: false
|
||||
@@ -1,5 +1,3 @@
|
||||
const path = require("path");
|
||||
const historyApiFallback = require("connect-history-api-fallback");
|
||||
const chalk = require("chalk");
|
||||
const express = require("express");
|
||||
const favicon = require("serve-favicon");
|
||||
@@ -11,35 +9,51 @@ const utils = require("./utils");
|
||||
process.env.NODE_ENV = "development";
|
||||
|
||||
const CLIENT_PORT = process.env.CXG_CLIENT_PORT;
|
||||
const { CXG_SERVER_PORT } = process.env;
|
||||
|
||||
const API = {
|
||||
prefix: `http://localhost:${CXG_SERVER_PORT}/`,
|
||||
};
|
||||
|
||||
// Set up compiler
|
||||
const compiler = webpack(config);
|
||||
|
||||
compiler.plugin("invalid", () => {
|
||||
compiler.hooks.invalid.tap("invalid", () => {
|
||||
utils.clearConsole();
|
||||
console.log("Compiling...");
|
||||
});
|
||||
|
||||
compiler.plugin("done", (stats) => {
|
||||
compiler.hooks.done.tap("done", (stats) => {
|
||||
utils.formatStats(stats, CLIENT_PORT);
|
||||
});
|
||||
|
||||
// Launch server
|
||||
const app = express();
|
||||
|
||||
app.use(historyApiFallback({ verbose: false }));
|
||||
|
||||
app.use(
|
||||
devMiddleware(compiler, {
|
||||
logLevel: "warn",
|
||||
publicPath: config.output.publicPath,
|
||||
index: true,
|
||||
})
|
||||
);
|
||||
|
||||
app.use(favicon("./favicon.png"));
|
||||
|
||||
app.get("*", (req, res) => {
|
||||
res.sendFile(path.resolve("index.html"));
|
||||
app.get("/login", async (req, res) => {
|
||||
try {
|
||||
res.redirect(`${API.prefix}login?dataset=http://localhost:${CLIENT_PORT}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/logout", async (req, res) => {
|
||||
try {
|
||||
res.redirect(`${API.prefix}logout?dataset=http://localhost:${CLIENT_PORT}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(CLIENT_PORT, (err) => {
|
||||
|
||||
@@ -51,7 +51,11 @@ const Auth = React.memo((props) => {
|
||||
|
||||
return (
|
||||
<Popover content={PopoverContent}>
|
||||
<Button className={styles.menubarButton} style={{ padding: 0 }}>
|
||||
<Button
|
||||
data-testid="user-info"
|
||||
className={styles.menubarButton}
|
||||
style={{ padding: 0 }}
|
||||
>
|
||||
{userinfo?.picture ? (
|
||||
<img alt="profile" src={userinfo?.picture} />
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user