Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
98eb9c1
docs: Remove S.4 save/publish from manual test cases
dcalhoun Feb 20, 2026
8adfb56
test: Add wp-env fixtures and migrate EditorPage to wp-env
dcalhoun Feb 20, 2026
8587cfe
test: Add test media assets for E2E upload tests
dcalhoun Feb 20, 2026
09f4484
test: Add E2E tests for media uploads (S.2, S.3, F.4, F.6, F.7)
dcalhoun Feb 20, 2026
25ce6ac
test: Add E2E tests for editor features (F.1, F.2, F.3, F.5)
dcalhoun Feb 20, 2026
532ae0e
docs: Remove automated test cases from test-cases.md
dcalhoun Feb 20, 2026
25ec72c
test: Remove legacy test case ID suffixes from describe blocks
dcalhoun Feb 20, 2026
d93ec3c
ci: Run E2E tests on Linux with Docker for wp-env support
dcalhoun Feb 20, 2026
1bb9402
ci: Revert E2E test task to macOS agent
dcalhoun Feb 20, 2026
3f7b1d8
Trying to use `mac-metal` as the queue to see if the issue with Playw…
AliSoftware Feb 20, 2026
2e1ca21
Revert "Trying to use `mac-metal` as the queue to see if the issue wi…
AliSoftware Feb 20, 2026
96e4784
Attempt to install Docker.
twstokes Feb 24, 2026
3d60ca9
Don't install Docker because it's reporting that it's already installed.
twstokes Feb 24, 2026
ae64f1a
ci: Add Docker diagnostic logging to E2E step on macOS agent
dcalhoun Feb 25, 2026
5766f3c
ci: Install Playwright system deps on Linux agent before E2E tests
dcalhoun Feb 25, 2026
3e0d845
ci: Add DEBIAN_FRONTEND=noninteractive to Playwright deps install
dcalhoun Feb 25, 2026
f4c51f6
ci: Add diagnostics for default Linux queue capabilities
dcalhoun Feb 25, 2026
b584029
ci: Run Playwright E2E tests inside Docker container
dcalhoun Feb 25, 2026
380fb1b
ci: Use --userns=host to allow --network host in Playwright container
dcalhoun Feb 25, 2026
c7d97b8
ci: Add wp-env diagnostics to debug editor settings 404
dcalhoun Feb 26, 2026
0b1a2c3
ci: Debug wp-env REST API permalink issue
dcalhoun Feb 26, 2026
19aa5e5
fix: Write .htaccess directly in wp-env for pretty permalinks
dcalhoun Feb 26, 2026
accf493
fix: Use wp eval to write .htaccess with correct permissions
dcalhoun Feb 26, 2026
fa0cc52
fix: Use docker exec as root to write .htaccess
dcalhoun Feb 26, 2026
b7a1475
fix: Find wp-env container by published port instead of image name
dcalhoun Feb 26, 2026
0ee835c
test: Add network request logging to image upload test
dcalhoun Feb 26, 2026
368e641
ci: Dump WordPress debug log and uploads permissions after E2E tests
dcalhoun Feb 26, 2026
98646f7
ci: Prevent script abort so WordPress debug log is captured
dcalhoun Feb 26, 2026
ebc7f76
ci: Fix root-owned files left by Playwright container
dcalhoun Feb 26, 2026
7cdb8ee
ci: Capture wp-env container ID before Playwright overwrites node_mod…
dcalhoun Feb 27, 2026
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
35 changes: 34 additions & 1 deletion .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,40 @@ steps:
command: |
buildkite-agent artifact download dist.tar.gz .
tar -xzf dist.tar.gz
make test-e2e
echo "--- :docker: Starting wp-env"
make wp-env-start
WP_CONTAINER=$(docker ps -qf "publish=8888" | head -1)
echo "--- :performing_arts: Running E2E tests in Playwright container"
E2E_EXIT=0
docker run --rm \
--userns=host \
--network host \
-v "$(pwd):/work" \
-w /work \
-e CI=true \
mcr.microsoft.com/playwright:v1.58.2-noble \
bash -c "npm ci && npx playwright install chromium && npx playwright test" \
|| E2E_EXIT=$?
echo "--- :broom: Fixing ownership of root-owned files"
docker run --rm \
--userns=host \
-v "$(pwd):/work" \
-w /work \
mcr.microsoft.com/playwright:v1.58.2-noble \
chown -R "$(id -u):$(id -g)" /work
echo "--- :wordpress: WordPress debug log"
if [ -n "$WP_CONTAINER" ]; then
docker exec "$WP_CONTAINER" cat /var/www/html/wp-content/debug.log 2>/dev/null || echo "(no debug.log found)"
echo "--- :file_folder: Uploads directory permissions"
docker exec "$WP_CONTAINER" ls -la /var/www/html/wp-content/uploads/ 2>/dev/null || echo "(no uploads directory)"
echo "--- :whale: WordPress container status"
docker inspect --format='{{.State.Status}}' "$WP_CONTAINER" 2>/dev/null || echo "(container gone)"
else
echo "(WordPress container not found before tests)"
fi
exit $E2E_EXIT
agents:
queue: default
plugins: *plugins

- label: ':android: Publish Android Library'
Expand Down
26 changes: 25 additions & 1 deletion bin/wp-env-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,31 @@ done
# ---------------------------------------------------------------------------

echo "Flushing rewrite rules..."
npm run --silent wp-env run cli -- wp rewrite structure '/%postname%/' --hard 2>/dev/null
npm run --silent wp-env run cli -- wp rewrite structure '/%postname%/' 2>/dev/null

echo "Writing .htaccess for pretty permalinks..."
WP_CONTAINER=$(docker ps -qf "publish=8888" | head -1)
if [ -z "$WP_CONTAINER" ]; then
echo "Error: Could not find WordPress container on port 8888."
echo "Running containers:"
docker ps --format "{{.ID}} {{.Image}} {{.Ports}} {{.Names}}"
exit 1
fi
echo "Found WordPress container: $WP_CONTAINER"
docker exec -u 0 "$WP_CONTAINER" sh -c 'cat > /var/www/html/.htaccess << "HTACCESS"
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
HTACCESS
'

# ---------------------------------------------------------------------------
# Enable Jetpack blocks module
Expand Down
84 changes: 2 additions & 82 deletions docs/test-cases.md
Original file line number Diff line number Diff line change
@@ -1,90 +1,10 @@
# Mobile Editor Tests

## Smoke Tests
These test cases require the native undo/redo toolbar and must be verified manually on iOS or Android.

**Purpose:** Verify the editor's core functionality: writing/formatting text, uploading media, saving/publishing, and basic block manipulation.

### S.1. Undo/Redo Actions
## S.1. Undo/Redo Actions

- **Steps:**
- Add, remove, and edit blocks and text.
- Use Undo and Redo buttons.
- **Expected Outcome:** Editor correctly undoes and redoes actions, restoring previous states.

### S.2. Upload an image

- **Steps:**
- Add an Image block.
- Tap "Choose from device" and select an image.
- **Expected Outcome:** Image uploads and displays in the block. An activity indicator is shown while the image is uploading.

### S.3. Upload an video

- **Steps:**
- Add a Video block.
- Tap "Choose from device" and select a video.
- **Expected Outcome:** Video uploads and displays in the block. An activity indicator is shown while the video is uploading.

### S.4. Save and publish a post

- **Steps:**
- Create a new post with text and media.
- Save as draft, then publish.
- **Expected Outcome:** Post is saved and published successfully; content appears as expected.

## Functionality Tests

**Purpose:** Validate deeper content and formatting features, advanced block settings, and robust editor behaviors.

### F.1. Text alignment options

- **Steps:**
- Add a Paragraph or Verse block.
- Type text and use alignment options (left, center, right).
- **Expected Outcome:** Selected alignment is applied to the block content.

### F.2. Add and preview embedded content

- **Steps:**
- Add a Shortcode or Embed block.
- Insert a YouTube or Twitter link.
- Preview the post.
- **Expected Outcome:** Embedded content (e.g., YouTube video) displays correctly in preview.

### F.3. Color and gradient customization

- **Steps:**
- Add a block supporting color (e.g., Buttons, Cover).
- Open color settings, switch between solid and gradient, pick custom colors, and apply.
- **Expected Outcome:** Selected colors/gradients are applied; UI updates accordingly.

### F.4. Gallery block: image uploads and captions

- **Steps:**
- Add a Gallery block, upload multiple images.
- Add captions to gallery and individual images, apply formatting.
- **Expected Outcome:** An activity indicator is shown while the images are uploading. Captions and formatting display as expected.

### F.5. Pattern insertion

- **Steps:**
- Insert a pattern from the inserter.
- **Expected Outcome:** Pattern content appears.

### F.6. Upload an audio file

Known issue: [Audio block unable to upload expected file formats](https://github.com/wordpress-mobile/GutenbergKit/issues/123)

- **Steps:**
- Add an Audio block.
- Tap "Choose from device" and select an audio file.
- **Expected Outcome:** Audio uploads and displays in the block. An activity indicator is shown while the audio is uploading.

### F.7. Upload a file

Known issue: [File block unable to upload expected file formats](https://github.com/wordpress-mobile/GutenbergKit/issues/124)

- **Steps:**
- Add a File block.
- Tap "Choose from device" and select a file.
- **Expected Outcome:** File uploads, filename and download button appear when upload completes.
Binary file added e2e/assets/test-audio.mp3
Binary file not shown.
Binary file added e2e/assets/test-file.pdf
Binary file not shown.
Binary file added e2e/assets/test-image-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added e2e/assets/test-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added e2e/assets/test-video.mp4
Binary file not shown.
39 changes: 39 additions & 0 deletions e2e/audio-upload.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* External dependencies
*/
import path from 'node:path';
import { test, expect } from '@playwright/test';

/**
* Internal dependencies
*/
import EditorPage from './editor-page';

const TEST_AUDIO = path.resolve( import.meta.dirname, 'assets/test-audio.mp3' );

test.describe( 'Audio Upload', () => {
test( 'should upload an audio file via the Audio block', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup();

await editor.insertBlock( 'core/audio' );

// Use the "Upload" button which triggers a file input.
const fileChooserPromise = page.waitForEvent( 'filechooser' );
await page
.getByRole( 'button', { name: 'Upload', exact: true } )
.click();
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles( TEST_AUDIO );

// Wait for the upload to complete (block gets a numeric media ID).
const attrs = await editor.waitForMediaUpload( 0 );
expect( attrs.id ).toBeGreaterThan( 0 );
expect( attrs.src ).toContain( 'localhost:8888' );

// Verify the audio element is rendered.
await expect( page.locator( '.wp-block-audio audio' ) ).toBeAttached();
} );
} );
104 changes: 104 additions & 0 deletions e2e/color-gradient.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* External dependencies
*/
import { test, expect } from '@playwright/test';

/**
* Internal dependencies
*/
import EditorPage from './editor-page';

test.describe( 'Color and Gradient', () => {
test( 'should apply a background color to a button via settings', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup();

await editor.insertBlock( 'core/buttons' );

// Type into the button so the inner button block is focused.
const buttonText = page.getByRole( 'textbox', {
name: 'Button text',
} );
await buttonText.click();
await page.keyboard.type( 'Colored' );

// Open block settings and navigate to the Styles tab.
await editor.openBlockSettings();
await page.getByRole( 'tab', { name: 'Styles' } ).click();

// Click the Background color control.
await page
.locator( '.block-settings-menu' )
.getByRole( 'button', { name: 'Background' } )
.click();

// Pick the first color option in the palette.
await page
.locator( '.components-circular-option-picker__option' )
.first()
.click();

// Close the settings popover before reading attributes.
await page.keyboard.press( 'Escape' );

// Verify the inner button block got a background color.
const blocks = await editor.getBlocks();
const innerButton = blocks[ 0 ].innerBlocks[ 0 ];
expect(
innerButton.attributes.backgroundColor ||
innerButton.attributes.style?.color?.background
).toBeTruthy();
} );

test( 'should have theme gradients available in editor settings', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup();

// Verify that theme gradients are loaded from wp-env editor settings.
const hasGradients = await page.evaluate( () => {
const settings = window.wp.data
.select( 'core/block-editor' )
.getSettings();
return (
Array.isArray( settings.gradients ) &&
settings.gradients.length > 0
);
} );
expect( hasGradients ).toBe( true );
} );

test( 'should apply a gradient to a button via data store', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup();

await editor.insertBlock( 'core/buttons' );

// Apply a gradient to the inner button block via the data store.
await page.evaluate( () => {
const blocks = window.wp.data
.select( 'core/block-editor' )
.getBlocks();
const innerButton = blocks[ 0 ]?.innerBlocks?.[ 0 ];
if ( innerButton ) {
window.wp.data
.dispatch( 'core/block-editor' )
.updateBlockAttributes( innerButton.clientId, {
gradient: 'vivid-cyan-blue-to-vivid-purple',
} );
}
} );

// Verify the gradient was applied.
const blocks = await editor.getBlocks();
const innerButton = blocks[ 0 ].innerBlocks[ 0 ];
expect( innerButton.attributes.gradient ).toBe(
'vivid-cyan-blue-to-vivid-purple'
);
} );
} );
4 changes: 3 additions & 1 deletion e2e/editor-error.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ test.describe( 'Editor Error Handling', () => {
test( 'should show plugin load failure notice and keep editor functional', async ( {
page,
} ) => {
// Enable plugins without providing API endpoints. This causes
// Enable plugins with an unreachable API root. This causes
// fetchEditorAssets to fail, resulting in the plugin load notice.
const editor = new EditorPage( page );
await editor.setup( {
siteApiRoot: 'http://localhost:1/',
authHeader: '',
post: {
id: 1,
type: 'post',
Expand Down
Loading