Skip to content
Draft
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
22 changes: 22 additions & 0 deletions flow-client/src/test/frontend/FlowTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ import sinon from 'sinon';
const $wnd = window as any;
const flowRoot = window.document.body as any;

/**
* Stubs window.Vaadin.Flow.ready and whenReady with sentinel values so the
* preservation test can verify that constructing a Flow instance does not
* overwrite definitions from the inline bootstrap script. The real
* implementations live in flow-server's whenReady.js and are not tested here.
*/
const READY_SENTINEL = () => {};
const WHEN_READY_SENTINEL = () => {};
function stubWhenReady() {
$wnd.Vaadin = $wnd.Vaadin || {};
$wnd.Vaadin.Flow = $wnd.Vaadin.Flow || {};
$wnd.Vaadin.Flow.ready = READY_SENTINEL;
$wnd.Vaadin.Flow.whenReady = WHEN_READY_SENTINEL;
}

const stubVaadinPushSrc = '/src/test/frontend/stubVaadinPush.js';
let server: MockXhrServer;
// A `changes` array that adds a div with 'Foo' text to body
Expand Down Expand Up @@ -657,6 +672,13 @@ describe('Flow', () => {
expect($wnd.Vaadin.connectionState.state).to.equal(ConnectionState.RECONNECTING);
});

it('should preserve ready and whenReady defined by inline script after construction', () => {
stubWhenReady();
new Flow({ imports: () => {} });
expect($wnd.Vaadin.Flow.ready).to.equal(READY_SENTINEL);
expect($wnd.Vaadin.Flow.whenReady).to.equal(WHEN_READY_SENTINEL);
});

it('should pre-attach container element on every navigation', async () => {
stubServerRemoteFunction('foobar-12345');
mockInitResponse('foobar-12345');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ public class BootstrapHandler extends SynchronizedRequestHandler {
+ "/client.nocache.js";
private static final String BOOTSTRAP_JS = readResource(
"BootstrapHandler.js");
/**
* Inlined into the bootstrap {@code <script>}. Must not contain {@code //}
* comments — they would swallow the rest of the line if the inline script
* is collapsed to one line by HTML processing.
*/
public static final String WHEN_READY_JS = readResource("whenReady.js");
private static final String CSS_TYPE_ATTRIBUTE_VALUE = "text/css";

private static final String CAPTION = "caption";
Expand Down Expand Up @@ -1194,6 +1200,7 @@ private String getBootstrapJS(ObjectNode initialUIDL,
result = result.replace("{{GWT_STAT_EVENTS}}", "");
}

result = result.replace("{{WHEN_READY}}", WHEN_READY_JS);
result = result.replace("{{APP_ID}}", context.getAppId());
result = result.replace("{{CONFIG_JSON}}", appConfigString);
// {{INITIAL_UIDL}} should be the last replaced so that it may have
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,10 @@ private void addInitialFlow(ObjectNode initialJson, Document indexDocument,
indexDocument.head(), request);
Element elm = new Element(SCRIPT);
elm.attr(SCRIPT_INITIAL, "");
elm.appendChild(new DataNode("window.Vaadin = window.Vaadin || {};" + //
"window.Vaadin.TypeScript= " + initialJson.toString() + ";"));
elm.appendChild(new DataNode("window.Vaadin = window.Vaadin || {};"
+ "window.Vaadin.Flow = window.Vaadin.Flow || {};"
+ BootstrapHandler.WHEN_READY_JS + "window.Vaadin.TypeScript= "
+ initialJson.toString() + ";"));
indexDocument.head().insertChildren(0, elm);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};

if (!window.Vaadin.Flow.whenReady) {
{{WHEN_READY}}
}

/**
* Triggers a CSS animation on an element by adding a class, then
* removes the class when the animation ends.
Expand Down
27 changes: 27 additions & 0 deletions flow-server/src/main/resources/com/vaadin/flow/server/whenReady.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
window.Vaadin.Flow.ready = async function ({ timeout = 30000 } = {}) {
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const deadline = Date.now() + timeout;

const isIdle = () => {
if (document.readyState !== 'complete') return false;
if (window.Vaadin.Flow.devServerIsNotLoaded) return false;
const clients = window.Vaadin.Flow.clients;
if (!clients) return false;
const probes = Object.values(clients).filter((c) => typeof c.isActive === 'function');
if (probes.length === 0) return false;
return probes.every((c) => !c.isActive());
};

while (!isIdle()) {
if (Date.now() >= deadline) {
throw new Error('Vaadin.Flow.ready timed out after ' + timeout + 'ms');
}
await sleep(50);
}
};

window.Vaadin.Flow.whenReady = function (callback) {
window.Vaadin.Flow.ready()
.catch((e) => console.warn(e.message))
.then(callback);
};
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,14 @@ public void should_not_add_initialUidl_when_not_includeInitialBootstrapUidl()
Element initialUidlScript = findScript(scripts,
INITIAL_UIDL_SEARCH_STRING);

assertEquals(
"window.Vaadin = window.Vaadin || {};window.Vaadin.TypeScript= {};",
initialUidlScript.childNode(0).toString());
String scriptContent = initialUidlScript.childNode(0).toString();
assertTrue(
scriptContent.contains("window.Vaadin = window.Vaadin || {};"));
assertTrue(scriptContent
.contains("window.Vaadin.Flow = window.Vaadin.Flow || {};"));
assertTrue(scriptContent.contains("window.Vaadin.Flow.ready = "));
assertTrue(scriptContent.contains("window.Vaadin.Flow.whenReady = "));
assertTrue(scriptContent.contains("window.Vaadin.TypeScript= {};"));
assertEquals("", initialUidlScript.attr("initial"));
}

Expand Down Expand Up @@ -448,9 +453,14 @@ public void should_not_initialize_UI_and_add_initialUidl_when_invalid_route()
Elements scripts = document.head().getElementsByTag("script");
Element initialUidlScript = findScript(scripts,
INITIAL_UIDL_SEARCH_STRING);
assertEquals(
"window.Vaadin = window.Vaadin || {};window.Vaadin.TypeScript= {};",
initialUidlScript.childNode(0).toString());
String scriptContent = initialUidlScript.childNode(0).toString();
assertTrue(
scriptContent.contains("window.Vaadin = window.Vaadin || {};"));
assertTrue(scriptContent
.contains("window.Vaadin.Flow = window.Vaadin.Flow || {};"));
assertTrue(scriptContent.contains("window.Vaadin.Flow.ready = "));
assertTrue(scriptContent.contains("window.Vaadin.Flow.whenReady = "));
assertTrue(scriptContent.contains("window.Vaadin.TypeScript= {};"));
assertEquals("", initialUidlScript.attr("initial"));
assertNull(UI.getCurrent());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
<script type="text/javascript">
// Set specific flag for TB and make sure that there are no any clients.
// It allows to work correct waitForVaadin in TB
window.Vaadin = { Flow: { devServerIsNotLoaded: true } };
window.Vaadin = { Flow: { devServerIsNotLoaded: true, ready: false, whenReady: false } };

const delay = 200;
const poll = async () => {
Expand Down
Loading