Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Remote] Preserve PHP constants when saving a temporary site #1911

Merged
merged 5 commits into from
Oct 16, 2024
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
2,627 changes: 1,380 additions & 1,247 deletions packages/playground/blueprints/public/blueprint-schema-validator.js

Large diffs are not rendered by default.

46 changes: 30 additions & 16 deletions packages/playground/blueprints/public/blueprint-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,7 @@
"description": "Extra libraries to preload into the Playground instance."
},
"constants": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"$ref": "#/definitions/PHPConstants",
"description": "PHP Constants to define on every request"
},
"plugins": {
Expand Down Expand Up @@ -188,6 +185,12 @@
"type": "string",
"const": "wp-cli"
},
"PHPConstants": {
"type": "object",
"additionalProperties": {
"type": ["string", "boolean", "number"]
}
},
"FileReference": {
"anyOf": [
{
Expand Down Expand Up @@ -699,18 +702,7 @@
"deprecated": ". Use `themeData` instead."
},
"options": {
"type": "object",
"properties": {
"activate": {
"type": "boolean",
"description": "Whether to activate the theme after installing it."
},
"importStarterContent": {
"type": "boolean",
"description": "Whether to import the theme's starter content after installing it."
}
},
"additionalProperties": false,
"$ref": "#/definitions/InstallThemeOptions",
"description": "Optional installation options."
}
},
Expand Down Expand Up @@ -1364,6 +1356,28 @@
"activate": {
"type": "boolean",
"description": "Whether to activate the plugin after installing it."
},
"targetFolderName": {
"type": "string",
"description": "The name of the folder to install the plugin to. Defaults to guessing from pluginData"
}
},
"additionalProperties": false
},
"InstallThemeOptions": {
"type": "object",
"properties": {
"activate": {
"type": "boolean",
"description": "Whether to activate the theme after installing it."
},
"importStarterContent": {
"type": "boolean",
"description": "Whether to import the theme's starter content after installing it."
},
"targetFolderName": {
"type": "string",
"description": "The name of the folder to install the theme to. Defaults to guessing from themeData"
}
},
"additionalProperties": false
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/blueprints/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import '@php-wasm/node-polyfills';
export * from './lib/steps';
export * from './lib/steps/handlers';
export { runBlueprintSteps, compileBlueprint } from './lib/compile';
export type { Blueprint } from './lib/blueprint';
export type { Blueprint, PHPConstants } from './lib/blueprint';
export type {
CompiledStep,
CompiledBlueprint,
Expand Down
4 changes: 3 additions & 1 deletion packages/playground/blueprints/src/lib/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export type ExtraLibrary =
// Install WP-CLI during boot.
'wp-cli';

export type PHPConstants = Record<string, string | boolean | number>;

export interface Blueprint {
/**
* The URL to navigate to after the blueprint has been run.
Expand Down Expand Up @@ -69,7 +71,7 @@ export interface Blueprint {
/**
* PHP Constants to define on every request
*/
constants?: Record<string, string>;
constants?: PHPConstants;

/**
* WordPress plugins to install and activate
Expand Down
58 changes: 57 additions & 1 deletion packages/playground/website/playwright/e2e/website-ui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,63 @@ test('should switch between sites', async ({ website, browserName }) => {
);
});

test('should preserve PHP constants when saving a temporary site to OPFS', async ({
website,
browserName,
wordpress,
}) => {
test.skip(
browserName === 'webkit',
`This test relies on OPFS which isn't available in Playwright's flavor of Safari.`
);

// Start a site with a specific PHP constant.
const blueprint: Blueprint = {
landingPage: '/index.php',
constants: { E2E_TEST_CONSTANT: 'E2E_TEST_VALUE' },
steps: [
{
step: 'writeFile',
path: '/wordpress/index.php',
data: '<?php echo E2E_TEST_CONSTANT;',
},
],
};
await website.goto(`./#${JSON.stringify(blueprint)}`);

await website.ensureSiteManagerIsOpen();

await expect(website.page.getByText('Save')).toBeEnabled();
await website.page.getByText('Save').click();
// We shouldn't need to explicitly call .waitFor(), but the test fails without it.
// Playwright logs that something "intercepts pointer events", that's probably related.
await website.page.getByText('Save in this browser').waitFor();
await website.page.getByText('Save in this browser').click({ force: true });
await expect(
website.page.locator('[aria-current="page"]')
).not.toContainText('Temporary Playground', {
// Saving the site takes a while on CI
timeout: 90000,
});
await expect(website.page.getByLabel('Playground title')).not.toContainText(
'Temporary Playground'
);

await website.page
.locator('button')
.filter({ hasText: 'Temporary Playground' })
.click();

// Switch back to the stored site and confirm the PHP constant is still present.
await website.page
.getByLabel('Saved Playgrounds')
.locator('button')
.last()
.click();

await expect(wordpress.locator('body')).toContainText('E2E_TEST_VALUE');
});

SupportedPHPVersions.forEach(async (version) => {
/**
* WordPress 6.6 dropped support for PHP 7.0 and 7.1 and won't load on these versions.
Expand All @@ -92,7 +149,6 @@ SupportedPHPVersions.forEach(async (version) => {
version
);
});

});

Object.keys(MinifiedWordPressVersions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ export function Sidebar({
>
Saved Playgrounds
</Heading>
<MenuGroup className={css.sidebarList}>
<MenuGroup
className={css.sidebarList}
label="Saved Playgrounds"
>
{storedSites.map((site) => {
/**
* The `wordpress` site is selected when no site slug is provided.
Expand Down
20 changes: 18 additions & 2 deletions packages/playground/website/src/lib/site-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
* Playground CLI, Studio, WP-ENV, hosted environment etc.
*/

import { Blueprint, compileBlueprint } from '@wp-playground/blueprints';
import {
Blueprint,
PHPConstants,
compileBlueprint,
} from '@wp-playground/blueprints';
import { resolveBlueprintFromURL } from './state/url/resolve-blueprint-from-url';

/**
Expand Down Expand Up @@ -51,7 +55,9 @@ export interface SiteMetadata {
runtimeConfiguration: Pick<
Required<Blueprint>,
'features' | 'extraLibraries' | 'preferredVersions'
>;
> & {
constants?: PHPConstants;
};
originalBlueprint: Blueprint;
}

Expand Down Expand Up @@ -87,6 +93,16 @@ export async function createSiteMetadata(
},
features: compiledBlueprint.features,
extraLibraries: compiledBlueprint.extraLibraries,
/*
* Constants don't matter so much for temporary sites so let's
* use an empty object here. We can't easily figure out which
* additional constants were applied via playground.defineConstant()
* at this stage anyway.
*
* This property is only relevant for stored sites to ensure they're
* consistently applied across page reloads.
*/
constants: {},
},
};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { logger } from '@php-wasm/logger';
import { MountDescriptor } from '@wp-playground/remote';
import { MountDescriptor, PlaygroundClient } from '@wp-playground/remote';
import { PHPConstants } from '@wp-playground/blueprints';
import { saveDirectoryHandle } from '../opfs/opfs-directory-handle-storage';
import {
opfsSiteStorage,
Expand Down Expand Up @@ -158,6 +159,7 @@ export function persistTemporarySite(
},
})
);

await dispatch(
updateSiteMetadata({
slug: siteSlug,
Expand All @@ -166,6 +168,14 @@ export function persistTemporarySite(
// Reset the created date. Mental model: From the perspective of
// the storage backend, the site was just created.
whenCreated: Date.now(),
// Make sure to store the constants we'll want to re-apply
// on the next page load.
runtimeConfiguration: {
...siteInfo.metadata.runtimeConfiguration,
constants: await getPlaygroundDefinedPHPConstants(
playground
),
},
},
})
);
Expand All @@ -183,3 +193,15 @@ export function persistTemporarySite(
redirectTo(persistentSiteUrl);
};
}

async function getPlaygroundDefinedPHPConstants(playground: PlaygroundClient) {
let constants: PHPConstants = {};
try {
constants = JSON.parse(
await playground.readFileAsText('/internal/shared/consts.json')
);
} catch (error) {
// Do nothing
}
return constants;
}
Loading