Skip to content

Commit 952903e

Browse files
committed
init e2e tests with basic-usage spec
1 parent 95f2396 commit 952903e

File tree

9 files changed

+602
-4806
lines changed

9 files changed

+602
-4806
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"plugins": [
3+
"https://github.com/wp-graphql/wp-graphql/releases/latest/download/wp-graphql.zip",
4+
"."
5+
],
6+
"env": {
7+
"tests": {
8+
"plugins": [
9+
"https://github.com/wp-graphql/wp-graphql/releases/latest/download/wp-graphql.zip",
10+
".",
11+
"./tests/e2e/plugins/reset-wpgraphql-logging-settings/"
12+
]
13+
}
14+
},
15+
"config": {
16+
"WP_DEBUG": true
17+
},
18+
"mappings": {
19+
".htaccess": "./wp-env/setup/.htaccess"
20+
}
21+
}

plugins/wpgraphql-logging/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"author": "wpengine",
1515
"license": "GPL-2.0",
1616
"devDependencies": {
17-
"@playwright/test": "^1.52.0",
17+
"@playwright/test": "^1.56.1",
1818
"@wordpress/e2e-test-utils-playwright": "^1.25.0",
1919
"@wordpress/env": "^10.25.0",
2020
"@wordpress/jest-console": "^8.25.0",
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { request } from "@playwright/test";
2+
import { RequestUtils } from "@wordpress/e2e-test-utils-playwright";
3+
4+
async function globalSetup(config) {
5+
const { baseURL, storageState } = config.projects[0].use;
6+
const storageStatePath =
7+
typeof storageState === "string" ? storageState : undefined;
8+
9+
const requestContext = await request.newContext({
10+
baseURL,
11+
});
12+
13+
const requestUtils = new RequestUtils(requestContext, {
14+
storageStatePath,
15+
});
16+
17+
// Authenticate and save the storageState to disk.
18+
await requestUtils.setupRest();
19+
20+
await Promise.all([
21+
requestUtils.deleteAllPosts(),
22+
requestUtils.deleteAllPages(),
23+
requestUtils.resetPreferences(),
24+
]);
25+
26+
await requestContext.dispose();
27+
}
28+
29+
export default globalSetup;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const PLUGIN_SLUG = "wpgraphql-logging";
2+
export const RESET_HELPER_PLUGIN_SLUG = "reset-wpgraphql-logging-settings";
3+
export const GET_POSTS_QUERY = `
4+
query GetPosts {
5+
posts(first: 5) {
6+
nodes {
7+
id
8+
title
9+
date
10+
}
11+
}
12+
}
13+
`;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { defineConfig } from "@playwright/test";
2+
import baseConfig from "@wordpress/scripts/config/playwright.config";
3+
4+
const config = defineConfig({
5+
...baseConfig,
6+
globalSetup: require.resolve("./config/global-setup.js"),
7+
});
8+
9+
export default config;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
/**
3+
* Plugin Name: Reset WPGraphQL Logging settings
4+
* Description: This plugin resets WPGraphQL Logging settings on activation. It's only intended to be used for e2e testing purposes.
5+
*/
6+
7+
add_action('init', function () {
8+
if ($_SERVER['REQUEST_URI'] === '/wp-admin/options-general.php?page=wpgraphql-logging&reset=true') {
9+
global $wpdb;
10+
11+
// Reset settings
12+
update_option('wpgraphql_logging_settings', array());
13+
14+
// Clear logs table
15+
$table_name = $wpdb->prefix . 'wpgraphql_logging';
16+
$wpdb->query("TRUNCATE TABLE {$table_name}");
17+
}
18+
});
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { expect, test } from "@wordpress/e2e-test-utils-playwright";
2+
import {
3+
goToLoggingSettingsPage,
4+
goToLogsListPage,
5+
configureLogging,
6+
executeGraphQLQuery,
7+
resetPluginSettings,
8+
} from "../utils";
9+
import { GET_POSTS_QUERY } from "../constants";
10+
11+
test.describe("Configure WPGraphQL Logging Plugin and Verify Logging Works", () => {
12+
test.beforeEach(async ({ admin }) => {
13+
await resetPluginSettings(admin);
14+
});
15+
16+
test("should enable logging and verify GraphQL queries are being logged", async ({
17+
page,
18+
admin,
19+
request,
20+
}) => {
21+
// Set up logging settings
22+
await goToLoggingSettingsPage(admin);
23+
await expect(page.locator("h1")).toHaveText("WPGraphQL Logging Settings");
24+
25+
await configureLogging(page, {
26+
enabled: true,
27+
dataSampling: "100",
28+
eventLogSelection: ["graphql_request_results"],
29+
});
30+
31+
await expect(page.locator(".notice.notice-success")).toBeVisible();
32+
33+
// Execute a GraphQL query
34+
const response = await executeGraphQLQuery(request, GET_POSTS_QUERY);
35+
expect(response.ok()).toBeTruthy();
36+
37+
// Check that the log appears in the logs list
38+
await goToLogsListPage(admin);
39+
await expect(page.locator("h1")).toContainText("WPGraphQL Logs");
40+
41+
const logRow = page
42+
.locator("#the-list tr")
43+
.filter({ hasText: "GetPosts" })
44+
.first();
45+
await expect(logRow).toBeVisible({ timeout: 10000 });
46+
47+
// View log details
48+
const viewLink = logRow.locator(".row-actions .view a");
49+
await expect(viewLink).toBeVisible();
50+
await viewLink.focus();
51+
await viewLink.click();
52+
53+
await expect(page.locator("h1")).toContainText("Log Entry");
54+
55+
const logTable = page.locator(".widefat.striped");
56+
await expect(logTable).toBeVisible();
57+
58+
const queryRow = logTable
59+
.locator("tr")
60+
.filter({ has: page.locator("th", { hasText: "Query" }) });
61+
await expect(queryRow).toBeVisible();
62+
await expect(queryRow.locator("td pre")).toContainText("query GetPosts");
63+
64+
// Go back to logs list
65+
const backLink = page
66+
.locator("p a.button")
67+
.filter({ hasText: "Back to Logs" });
68+
await expect(backLink).toBeVisible();
69+
70+
await backLink.click();
71+
await expect(page.locator("h1")).toContainText("WPGraphQL Logs");
72+
});
73+
74+
test("should not log queries when logging is disabled", async ({
75+
page,
76+
admin,
77+
request,
78+
}) => {
79+
// Make sure there are no logs
80+
await goToLogsListPage(admin);
81+
await expect(
82+
page.locator('td.colspanchange:has-text("No items found.")')
83+
).toBeVisible();
84+
85+
// Disable logging
86+
await goToLoggingSettingsPage(admin);
87+
await configureLogging(page, {
88+
enabled: false,
89+
dataSampling: "100",
90+
});
91+
92+
await executeGraphQLQuery(request, GET_POSTS_QUERY);
93+
94+
// Navigate to logs and verify no new logs were created
95+
await goToLogsListPage(admin);
96+
await expect(
97+
page.locator('td.colspanchange:has-text("No items found.")')
98+
).toBeVisible();
99+
});
100+
});
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* Reset WPGraphQL Logging settings
3+
*/
4+
export async function resetPluginSettings(admin) {
5+
await admin.visitAdminPage(
6+
"/options-general.php?page=wpgraphql-logging&reset=true"
7+
);
8+
}
9+
10+
/**
11+
* Navigate to WPGraphQL Logging settings page
12+
*/
13+
export async function goToLoggingSettingsPage(admin) {
14+
await admin.visitAdminPage("/options-general.php?page=wpgraphql-logging");
15+
}
16+
17+
/**
18+
* Navigate to WPGraphQL Logs list page
19+
*/
20+
export async function goToLogsListPage(admin) {
21+
await admin.visitAdminPage("/admin.php?page=wpgraphql-logging-view");
22+
}
23+
24+
/**
25+
* Configure logging settings with common options
26+
*/
27+
export async function configureLogging(page, settings = {}) {
28+
const {
29+
enabled = true,
30+
dataSampling = "100",
31+
ipRestrictions = "",
32+
excludeQueries = "",
33+
logResponse = false,
34+
eventLogSelection = [],
35+
} = settings;
36+
37+
// Enable/disable logging
38+
const enabledCheckbox = page.locator(
39+
'input[name="wpgraphql_logging_settings[basic_configuration][enabled]"]'
40+
);
41+
if (enabled) {
42+
await enabledCheckbox.check();
43+
} else {
44+
await enabledCheckbox.uncheck();
45+
}
46+
47+
// Set data sampling
48+
await page
49+
.locator(
50+
'select[name="wpgraphql_logging_settings[basic_configuration][data_sampling]"]'
51+
)
52+
.selectOption(dataSampling);
53+
54+
// Set IP restrictions
55+
if (ipRestrictions) {
56+
await page
57+
.locator(
58+
'input[name="wpgraphql_logging_settings[basic_configuration][ip_restrictions]"]'
59+
)
60+
.fill(ipRestrictions);
61+
}
62+
63+
// Set exclude queries
64+
if (excludeQueries) {
65+
await page
66+
.locator(
67+
'input[name="wpgraphql_logging_settings[basic_configuration][exclude_query]"]'
68+
)
69+
.fill(excludeQueries);
70+
}
71+
72+
// Set log response
73+
const logResponseCheckbox = page.locator(
74+
'input[name="wpgraphql_logging_settings[basic_configuration][log_response]"]'
75+
);
76+
if (logResponse) {
77+
await logResponseCheckbox.check();
78+
} else {
79+
await logResponseCheckbox.uncheck();
80+
}
81+
82+
// Set event log selection (multi-select)
83+
if (eventLogSelection.length > 0) {
84+
const eventSelect = page.locator(
85+
'select[name="wpgraphql_logging_settings[basic_configuration][event_log_selection][]"]'
86+
);
87+
await eventSelect.selectOption(eventLogSelection);
88+
}
89+
90+
await page.getByRole("button", { name: "Save Changes" }).click();
91+
await page.waitForSelector(".notice.notice-success");
92+
}
93+
94+
/**
95+
* Execute a GraphQL query via the WordPress GraphQL endpoint
96+
*/
97+
export async function executeGraphQLQuery(request, query, variables = {}) {
98+
const response = await request.post("/graphql", {
99+
data: {
100+
query,
101+
variables,
102+
},
103+
headers: {
104+
"Content-Type": "application/json",
105+
},
106+
});
107+
108+
return response;
109+
}
110+
111+
/**
112+
* Get log details from a specific log entry
113+
*/
114+
export async function getLogDetails(page, logId) {
115+
// Navigate to the log detail page
116+
await page.goto(
117+
`/wp-admin/admin.php?page=wpgraphql-logging-view&action=view&log=${logId}`
118+
);
119+
120+
// Extract log details from the table
121+
const details = {};
122+
const rows = await page.locator(".widefat.striped tbody tr").all();
123+
124+
for (const row of rows) {
125+
const header = await row.locator("th").textContent();
126+
const value = await row.locator("td").textContent();
127+
details[header.trim()] = value.trim();
128+
}
129+
130+
return details;
131+
}

0 commit comments

Comments
 (0)