Skip to content
This repository has been archived by the owner on Jul 28, 2023. It is now read-only.

Commit

Permalink
Merge pull request #139 from WordPress/make-context-extensible
Browse files Browse the repository at this point in the history
Make `wp-context` inheritable and extensible
  • Loading branch information
DAreRodz authored Jan 26, 2023
2 parents f892bee + 2bcd43c commit 0a1de28
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 28 deletions.
114 changes: 114 additions & 0 deletions e2e/directives-context.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html>
<head>
<title>Directives -- wp-context</title>
<meta itemprop="wp-client-side-transitions" content="active" />
</head>

<body>
<div
wp-context='{ "prop1":"parent","prop2":"parent","obj":{"prop4":"parent","prop5":"parent"},"array":[1,2,3] }'
>
<pre
data-testid="parent context"
wp-bind:children="derived.renderContext"
>
<!-- rendered during hydration -->
</pre>
<button
data-testid="parent prop1"
name="prop1"
value="modifiedFromParent"
wp-on:click="actions.updateContext"
>
prop1
</button>
<button
data-testid="parent prop2"
name="prop2"
value="modifiedFromParent"
wp-on:click="actions.updateContext"
>
prop2
</button>
<button
data-testid="parent obj.prop4"
name="obj.prop4"
value="modifiedFromParent"
wp-on:click="actions.updateContext"
>
obj.prop4
</button>
<button
data-testid="parent obj.prop5"
name="obj.prop5"
value="modifiedFromParent"
wp-on:click="actions.updateContext"
>
obj.prop5
</button>
<div
wp-context='{ "prop2":"child","prop3":"child","obj":{"prop5":"child","prop6":"child"},"array":[4,5,6] }'
>
<pre
data-testid="child context"
wp-bind:children="derived.renderContext"
>
<!-- rendered during hydration -->
</pre>
<button
data-testid="child prop1"
name="prop1"
value="modifiedFromChild"
wp-on:click="actions.updateContext"
>
prop1
</button>
<button
data-testid="child prop2"
name="prop2"
value="modifiedFromChild"
wp-on:click="actions.updateContext"
>
prop2
</button>
<button
data-testid="child prop3"
name="prop3"
value="modifiedFromChild"
wp-on:click="actions.updateContext"
>
prop3
</button>
<button
data-testid="child obj.prop4"
name="obj.prop4"
value="modifiedFromChild"
wp-on:click="actions.updateContext"
>
obj.prop4
</button>
<button
data-testid="child obj.prop5"
name="obj.prop5"
value="modifiedFromChild"
wp-on:click="actions.updateContext"
>
obj.prop5
</button>
<button
data-testid="child obj.prop6"
name="obj.prop6"
value="modifiedFromChild"
wp-on:click="actions.updateContext"
>
obj.prop6
</button>
</div>
</div>

<script src="../build/e2e/wpx.js"></script>
<script src="../build/runtime.js"></script>
<script src="../build/vendors.js"></script>
</body>
</html>
135 changes: 135 additions & 0 deletions e2e/directives-context.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { join } from 'path';
import { test, expect, Locator } from '@playwright/test';

const parseContent = async (loc: Locator) =>
JSON.parse((await loc.textContent()) || '');

test.describe('wp-context', () => {
test.beforeEach(async ({ page }) => {
await page.goto('file://' + join(__dirname, 'directives-context.html'));
});

test('is correctly initialized', async ({ page }) => {
const parentContext = await parseContent(
page.getByTestId('parent context')
);

expect(parentContext).toMatchObject({
prop1: 'parent',
prop2: 'parent',
obj: { prop4: 'parent', prop5: 'parent' },
array: [1, 2, 3],
});
});

test('is correctly extended', async ({ page }) => {
const childContext = await parseContent(
page.getByTestId('child context')
);

expect(childContext).toMatchObject({
prop1: 'parent',
prop2: 'child',
prop3: 'child',
obj: { prop4: 'parent', prop5: 'child', prop6: 'child' },
array: [4, 5, 6],
});
});

test('changes in inherited properties are reflected (child)', async ({
page,
}) => {
await page.getByTestId('child prop1').click();
await page.getByTestId('child obj.prop4').click();

const childContext = await parseContent(
page.getByTestId('child context')
);

expect(childContext.prop1).toBe('modifiedFromChild');
expect(childContext.obj.prop4).toBe('modifiedFromChild');

const parentContext = await parseContent(
page.getByTestId('parent context')
);

expect(parentContext.prop1).toBe('modifiedFromChild');
expect(parentContext.obj.prop4).toBe('modifiedFromChild');
});

test('changes in inherited properties are reflected (parent)', async ({
page,
}) => {
await page.getByTestId('parent prop1').click();
await page.getByTestId('parent obj.prop4').click();

const childContext = await parseContent(
page.getByTestId('child context')
);

expect(childContext.prop1).toBe('modifiedFromParent');
expect(childContext.obj.prop4).toBe('modifiedFromParent');

const parentContext = await parseContent(
page.getByTestId('parent context')
);

expect(parentContext.prop1).toBe('modifiedFromParent');
expect(parentContext.obj.prop4).toBe('modifiedFromParent');
});

test('changes in shadowed properties do not leak (child)', async ({
page,
}) => {
await page.getByTestId('child prop2').click();
await page.getByTestId('child obj.prop5').click();

const childContext = await parseContent(
page.getByTestId('child context')
);

expect(childContext.prop2).toBe('modifiedFromChild');
expect(childContext.obj.prop5).toBe('modifiedFromChild');

const parentContext = await parseContent(
page.getByTestId('parent context')
);

expect(parentContext.prop2).toBe('parent');
expect(parentContext.obj.prop5).toBe('parent');
});

test('changes in shadowed properties do not leak (parent)', async ({
page,
}) => {
await page.getByTestId('parent prop2').click();
await page.getByTestId('parent obj.prop5').click();

const childContext = await parseContent(
page.getByTestId('child context')
);

expect(childContext.prop2).toBe('child');
expect(childContext.obj.prop5).toBe('child');

const parentContext = await parseContent(
page.getByTestId('parent context')
);

expect(parentContext.prop2).toBe('modifiedFromParent');
expect(parentContext.obj.prop5).toBe('modifiedFromParent');
});

test('Array properties are shadowed', async ({ page }) => {
const parentContext = await parseContent(
page.getByTestId('parent context')
);

const childContext = await parseContent(
page.getByTestId('child context')
);

expect(parentContext.array).toMatchObject([1, 2, 3]);
expect(childContext.array).toMatchObject([4, 5, 6]);
});
});
11 changes: 11 additions & 0 deletions e2e/wpx.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ wpx({
trueValue: true,
falseValue: false,
},
derived: {
renderContext: ({ context }) => {
return JSON.stringify(context, undefined, 2);
},
},
actions: {
toggleTrueValue: ({ state }) => {
state.trueValue = !state.trueValue;
Expand All @@ -15,5 +20,11 @@ wpx({
toggleContextFalseValue: ({ context }) => {
context.falseValue = !context.falseValue;
},
updateContext: ({ context, event }) => {
const { name, value } = event.target;
const [key, ...path] = name.split('.').reverse();
const obj = path.reduceRight((o, k) => o[k], context);
obj[key] = value;
},
},
});
Loading

0 comments on commit 0a1de28

Please sign in to comment.