Skip to content

Commit

Permalink
feat: add dependency handling for onUpdate hook (#1702)
Browse files Browse the repository at this point in the history
* feat: add dependency handling for onUpdate hook

* chore: update snapshots
fix: issue with e2e test

* fix: skip broken e2e tests for angular and solid
  • Loading branch information
nmerget authored Feb 27, 2025
1 parent 72cfea0 commit 997f673
Show file tree
Hide file tree
Showing 9 changed files with 375 additions and 93 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-oranges-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@builder.io/mitosis': patch
---

[stencil] add dependency handling for onUpdate hook
1 change: 1 addition & 0 deletions e2e/e2e-app/src/component-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const COMPONENT_PATHS = [
'/special-tags/',
'/signals/',
'/disabled-input/',
'/component-on-update/',
];
51 changes: 51 additions & 0 deletions e2e/e2e-app/src/components/component-on-update.lite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { onMount, onUpdate, useRef, useStore } from '@builder.io/mitosis';

type Store = { initial: boolean; counter: number; label?: string; handleClick: () => void };

export default function ComponentOnUpdate(props: any) {
const _ref = useRef<HTMLDivElement | null>(null);

const state = useStore<Store>({
initial: false,
counter: 0,
label: undefined,
handleClick: () => {
state.counter = state.counter + 1;
},
});

onMount(() => {
state.initial = true;
});

onUpdate(() => {
if (_ref && !state.initial) {
state.initial = true;
}
}, [_ref, state.initial]);

onUpdate(() => {
console.log(state.counter, state.label, state.initial);
});

onUpdate(() => {
if (state.initial) {
state.label = 'Label';
}
}, [state.initial]);

onUpdate(() => {
if (_ref && state.label) {
_ref.setAttribute('aria-label', `${state.label}: ${state.counter}`);
}
}, [_ref, state.counter, state.label]);

return (
<div ref={_ref} data-testid="container">
Hello {state.counter}
<button data-testid="button" onClick={() => state.handleClick()}>
Increase
</button>
</div>
);
}
5 changes: 5 additions & 0 deletions e2e/e2e-app/src/homepage.lite.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { For, onMount, Show, useStore } from '@builder.io/mitosis';
import { COMPONENT_PATHS } from './component-paths';
import ComponentOnUpdate from './components/component-on-update.lite';
import ComponentWithTypes from './components/component-with-types.lite';
import DisabledInput from './components/disabled-input/disabled-input.lite';
import NestedParent from './components/nested/nested-parent.lite';
Expand Down Expand Up @@ -61,6 +62,10 @@ export default function Homepage(props: { pathname?: string }) {
<Show when={state.pathToUse.startsWith('/disabled-input')}>
<DisabledInput />
</Show>

<Show when={state.pathToUse.startsWith('/component-on-update')}>
<ComponentOnUpdate />
</Show>
</div>
);
}
50 changes: 34 additions & 16 deletions e2e/e2e-app/tests/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,27 +80,45 @@ test.describe('e2e', () => {
const div = page.locator('.wrap');
await expect(div).toHaveCSS('background-color', 'rgb(255, 0, 0)');
});
});

test('simple input disabled', async ({ page, packageName }) => {
await page.goto('/disabled-input/');

test('simple input disabled', async ({ page, packageName }) => {
await page.goto('/disabled-input/');
const disabled = page.getByTestId('simple-input-disabled');
await expect(disabled).toBeDisabled();

const disabled = page.getByTestId('simple-input-disabled');
const enabled = page.getByTestId('simple-input-enabled');
if (['e2e-angular'].includes(packageName)) {
// this is the exception for angular it will generate [attr.disabled]
// which will be a string, so it is always true
await expect(disabled).toBeDisabled();
} else {
await expect(enabled).toBeEditable();
}

const enabled = page.getByTestId('simple-input-enabled');
if (['e2e-angular'].includes(packageName)) {
// this is the exception for angular it will generate [attr.disabled]
// which will be a string, so it is always true
await expect(disabled).toBeDisabled();
} else {
await expect(enabled).toBeEditable();
}
const nativeDisabled = page.getByTestId('native-input-disabled');
await expect(nativeDisabled).toBeDisabled();

const nativeDisabled = page.getByTestId('native-input-disabled');
await expect(nativeDisabled).toBeDisabled();
const nativeEnabled = page.getByTestId('native-input-enabled');
await expect(nativeEnabled).toBeEditable();
});

const nativeEnabled = page.getByTestId('native-input-enabled');
await expect(nativeEnabled).toBeEditable();
});
test('on update', async ({ page, packageName }) => {
if (['e2e-angular', 'e2e-solid'].includes(packageName)) {
// Angular: We need to split onUpdate to ngOnChanges and for useRef into ngAfterContentChecked
test.skip();
}

await page.goto('/component-on-update/');

const container = page.getByTestId('container');
const button = page.getByTestId('button');
const labelBefore = await container.getAttribute('aria-label');
expect(labelBefore).toEqual('Label: 0');

await button.click();
const labelAfter = await container.getAttribute('aria-label');
expect(labelAfter).toEqual('Label: 1');
});
});
1 change: 1 addition & 0 deletions e2e/e2e-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Mitosis output for not yet include .d.ts, so ignore the types when importing.
// Trigger nx remote cache: 2
// @ts-ignore
import { E2eApp } from '@builder.io/e2e-app/react';

Expand Down
Loading

0 comments on commit 997f673

Please sign in to comment.