Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig } from "cypress";
import { grantAdminRole, deleteUser } from "./cypress/e2e/contexts/user/tasks";
import { deleteTorrent } from "./cypress/e2e/contexts/torrent/tasks";
import { deleteCategory } from "./cypress/e2e/contexts/category/tasks";
import { deleteCategory, addCategory } from "./cypress/e2e/contexts/category/tasks";
import { DatabaseConfig } from "./cypress/e2e/common/database";

function databaseConfig (config: Cypress.PluginConfigOptions): DatabaseConfig {
Expand All @@ -15,17 +15,23 @@ export default defineConfig({
baseUrl: "http://localhost:3000",
setupNodeEvents (on, config) {
on("task", {
grantAdminRole: ({ username }) => {
return grantAdminRole(username, databaseConfig(config));
// Category context
deleteCategory: ({ name }) => {
return deleteCategory(name, databaseConfig(config));
},
addCategory: ({ name }) => {
return addCategory(name, databaseConfig(config));
},
// Torrent context
deleteTorrent: ({ infohash }) => {
return deleteTorrent(infohash, databaseConfig(config));
},
// User context
grantAdminRole: ({ username }) => {
return grantAdminRole(username, databaseConfig(config));
},
deleteUser: ({ username }) => {
return deleteUser(username, databaseConfig(config));
},
deleteCategory: ({ name }) => {
return deleteCategory(name, databaseConfig(config));
}
});
}
Expand Down
6 changes: 6 additions & 0 deletions cypress/e2e/common/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Common commands

Cypress.Commands.add("go_to_settings", () => {
cy.get("div[data-cy=\"user-menu\"]").click();
cy.get("li[data-cy=\"admin-settings-link\"]").click();
});
6 changes: 5 additions & 1 deletion cypress/e2e/contexts/category/commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Custom commands for category context

Cypress.Commands.add("delete_category", (name) => {
Cypress.Commands.add("delete_category_from_database", (name) => {
cy.task("deleteCategory", { name });
});

Cypress.Commands.add("add_category_to_database", (name) => {
cy.task("addCategory", { name });
});
7 changes: 7 additions & 0 deletions cypress/e2e/contexts/category/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function random_category_name (): string {
return `category-${random_category_id()}`;
}

function random_category_id (): number {
return Math.floor(Math.random() * 1000000);
}
21 changes: 10 additions & 11 deletions cypress/e2e/contexts/category/specs/add.cy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { RegistrationForm, random_user_registration_data } from "../../user/registration";
import { random_category_name } from "../fixtures";

describe("The admin user", () => {
let registration_form: RegistrationForm;
Expand All @@ -9,30 +10,30 @@ describe("The admin user", () => {
});

after(() => {
cy.delete_user(registration_form.username);
cy.delete_user_from_database(registration_form.username);
});

it("should be able to add a new category", () => {
const category_name = random_category_name();

// Make sure the category does not exist
cy.delete_category("new category");
cy.delete_category_from_database(category_name);

// Go to admin settings
cy.get("div[data-cy=\"user-menu\"]").click();
cy.get("li[data-cy=\"admin-settings-link\"]").click();
cy.go_to_settings();

// Click categories tab
cy.contains("a", "categories").click();

// Fill new category name
cy.get("input[data-cy=\"add-category-input\"]").type("new category");
cy.get("input[data-cy=\"add-category-input\"]").type(category_name);

// Add category
cy.get("button[data-cy=\"add-category-button\"]").click();

// The new category should appear in the list
cy.contains("new category (0)");
cy.contains(`${category_name} (0)`);

cy.delete_category("new category");
cy.delete_category_from_database(category_name);
});
});

Expand All @@ -45,20 +46,18 @@ describe("A non admin authenticated user", () => {
});

after(() => {
cy.delete_user(registration_form.username);
cy.delete_user_from_database(registration_form.username);
});

it("should not be able to add a new category", () => {
cy.visit("/admin/settings/categories");

cy.contains("Please login to manage admin settings.");
});
});

describe("A guest user", () => {
it("should not be able to add a new category", () => {
cy.visit("/admin/settings/categories");

cy.contains("Please login to manage admin settings.");
});
});
64 changes: 64 additions & 0 deletions cypress/e2e/contexts/category/specs/delete.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { RegistrationForm, random_user_registration_data } from "../../user/registration";
import { random_category_name } from "../fixtures";

describe("The admin user", () => {
let registration_form: RegistrationForm;

before(() => {
registration_form = random_user_registration_data();
cy.register_as_admin_and_login(registration_form);
});

after(() => {
cy.delete_user_from_database(registration_form.username);
});

it("should be able to delete a category", () => {
const category_name = random_category_name();

cy.add_category_to_database(category_name);

cy.go_to_settings();

// Click categories tab
cy.contains("a", "categories").click();

// Delete the category
cy.get(`button[data-cy="delete-category-${category_name}"]`).click();

// Confirm alert should pop up
cy.on("window:confirm", (str) => {
expect(str).to.equal(`Are you sure you want to delete ${category_name}?`);
});

// Confirm delete
cy.on("window:confirm", () => true);

cy.get(`[data-cy="delete-category-${category_name}"]`).should("not.exist");
});
});

describe("A non admin authenticated user", () => {
let registration_form: RegistrationForm;

before(() => {
registration_form = random_user_registration_data();
cy.register_and_login(registration_form);
});

after(() => {
cy.delete_user_from_database(registration_form.username);
});

it("should not be able to delete category", () => {
cy.visit("/admin/settings/categories");
cy.contains("Please login to manage admin settings.");
});
});

describe("A guest user", () => {
it("should not be able to delete a category", () => {
cy.visit("/admin/settings/categories");
cy.contains("Please login to manage admin settings.");
});
});
17 changes: 17 additions & 0 deletions cypress/e2e/contexts/category/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ export const deleteCategory = async (name: string, db_config: DatabaseConfig): P
}
};

// Task to add a new category
export const addCategory = async (name: string, db_config: DatabaseConfig): Promise<string> => {
try {
const result = await runDatabaseQuery(addCategoryQuery(name), db_config);
return name;
} catch (err) {
return await Promise.reject(err);
}
};

// Database query specifications

function deleteCategoryQuery (name: string): DatabaseQuery {
Expand All @@ -20,3 +30,10 @@ function deleteCategoryQuery (name: string): DatabaseQuery {
params: [name]
};
}

function addCategoryQuery (name: string): DatabaseQuery {
return {
query: "INSERT INTO torrust_categories (name) VALUES (?)",
params: [name]
};
}
2 changes: 1 addition & 1 deletion cypress/e2e/contexts/torrent/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Cypress.Commands.add("upload_torrent", (torrent_info) => {
cy.get("button[data-cy=\"upload-form-submit\"]").click();
});

Cypress.Commands.add("delete_torrent", (torrent_info, infohash) => {
Cypress.Commands.add("delete_torrent_from_database_and_fixture", (torrent_info, infohash) => {
// Delete the torrent in the database
cy.task("deleteTorrent", { infohash });

Expand Down
8 changes: 4 additions & 4 deletions cypress/e2e/contexts/torrent/specs/download.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe("A registered user", () => {
});

after(() => {
cy.delete_user(registration_form.username);
cy.delete_user_from_database(registration_form.username);
});

it("should be able to download a preexisting torrent", () => {
Expand All @@ -32,7 +32,7 @@ describe("A registered user", () => {

// Delete the test torrent generated for this test
const torrentInfoHash = parseInfoHash(interception.response.headers["x-torrust-torrent-infohash"]);
cy.delete_torrent(torrent_info, torrentInfoHash);
cy.delete_torrent_from_database_and_fixture(torrent_info, torrentInfoHash);
});
});
});
Expand All @@ -49,7 +49,7 @@ describe("A guest user", () => {
});

after(() => {
cy.delete_user(uploader_registration_form.username);
cy.delete_user_from_database(uploader_registration_form.username);
});

it("should be able to download a preexisting torrent", () => {
Expand Down Expand Up @@ -79,7 +79,7 @@ describe("A guest user", () => {

// Delete the test torrent generated for this test
const torrentInfoHash = parseInfoHash(interception.response.headers["x-torrust-torrent-infohash"]);
cy.delete_torrent(torrent_info, torrentInfoHash);
cy.delete_torrent_from_database_and_fixture(torrent_info, torrentInfoHash);
});
});
});
2 changes: 1 addition & 1 deletion cypress/e2e/contexts/torrent/specs/upload.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe("A registered user", () => {
});

after(() => {
cy.delete_user(registration_form.username);
cy.delete_user_from_database(registration_form.username);
});

it("should be able to upload a torrent", () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/contexts/user/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Cypress.Commands.add("register_as_admin", (registration_form) => {
cy.task("grantAdminRole", { username: registration_form.username });
});

Cypress.Commands.add("delete_user", (username) => {
Cypress.Commands.add("delete_user_from_database", (username) => {
cy.task("deleteUser", { username });
});

Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/contexts/user/specs/authentication.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("A registered user", () => {

cy.url().should("include", "/torrents");

cy.delete_user(registration_form.username);
cy.delete_user_from_database(registration_form.username);
});
});

Expand All @@ -40,6 +40,6 @@ describe("The website admin", () => {
// If the user is an admin, the link to admin settings should be available
cy.get("li[data-cy=\"admin-settings-link\"]");

cy.delete_user(registration_form.username);
cy.delete_user_from_database(registration_form.username);
});
});
25 changes: 17 additions & 8 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import "../e2e/contexts/user/commands";
import "../e2e/contexts/torrent/commands";
import "../e2e/contexts/category/commands";
import "../e2e/common/commands";
import { RegistrationForm } from "../e2e/contexts/user/registration";
import { TestTorrentInfo } from "cypress/e2e/contexts/torrent/test_torrent_info";

declare global {
namespace Cypress {
interface Chainable {
// User: Registration
// Common command
go_to_settings(): Chainable<void>

// User context: Registration
register(registration_form: RegistrationForm): Chainable<void>
register_as_admin(registration_form: RegistrationForm): Chainable<void>
delete_user(username: string): Chainable<void>
// User: Authentication

// User context: Authentication
login(username: string, password: string): Chainable<void>
logout(): Chainable<void>
// User: others

// User context: Others
register_and_login(registration_form: RegistrationForm): Chainable<void>
register_as_admin_and_login(registration_form: RegistrationForm): Chainable<void>
// Torrent
delete_user_from_database(username: string): Chainable<void>

// Torrent context
upload_torrent(torrent_info: TestTorrentInfo): Chainable<void>
delete_torrent(torrent_info: TestTorrentInfo, infohash: string): Chainable<void>
// Category
delete_category(name: string): Chainable<void>
delete_torrent_from_database_and_fixture(torrent_info: TestTorrentInfo, infohash: string): Chainable<void>

// Category context
delete_category_from_database(name: string): Chainable<void>
add_category_to_database(name: string): Chainable<void>
}
}
}
10 changes: 9 additions & 1 deletion pages/admin/settings/categories.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<template v-for="category in categories">
<div class="flex justify-between p-2 rounded bg-base-100">
<span class="text-base-content">{{ category.name }} ({{ category.num_torrents }})</span>
<button class="text-error-content hover:text-error" @click="deleteCategory(category.name)">
<button :data-cy="getDeleteButtonDataCy(category.name)" class="text-error-content hover:text-error" @click="deleteCategory(category.name)">
Delete
</button>
</div>
Expand All @@ -30,6 +30,14 @@ const rest = useRestApi().value;
const newCategory = ref("");
const addingCategory = ref(false);

onBeforeMount(() => {
getCategories();
});

function getDeleteButtonDataCy (name: string) {
return "delete-category-" + name.toLowerCase().replace(/ /g, "-");
}

function addCategory () {
if (newCategory.value) {
addingCategory.value = true;
Expand Down