17
global.TextEncoder = require('util').TextEncoder;
18
global.TextDecoder = require('util').TextDecoder;
19
20
+// Polyfill stream methods on JSDOM.
21
+global.Blob.prototype.stream = function () {
22
+ const impl = Object.getOwnPropertySymbols(this)[0];
23
+ const buffer = this[impl]._buffer;
24
+ return new ReadableStream({
25
+ start(c) {
26
+ c.enqueue(new Uint8Array(buffer));
27
+ c.close();
28
+ },
29
+ });
30
+};
31
+
32
+global.Blob.prototype.text = async function () {
33
+ const impl = Object.getOwnPropertySymbols(this)[0];
34
+ return this[impl]._buffer.toString('utf8');
35
+};
36
+
37
// Don't wait before processing work on the server.
38
// TODO: we can replace this with FlightServer.act().
39
global.setTimeout = cb => cb();
979
expect(form2.textContent).toBe('error message');
980
expect(form2.firstChild.tagName).toBe('DIV');
981
});
982
+
983
+ // @gate enableAsyncActions && enableBinaryFlight
984
+ it('useActionState can return binary state during MPA form submission', async () => {
985
+ const serverAction = serverExports(
986
+ async function action(prevState, formData) {
987
+ return new Blob([new Uint8Array([104, 105])]);
988
+ },
989
+ );
990
+
991
+ let blob;
992
+
993
+ function Form({action}) {
994
+ const [errorMsg, dispatch] = useActionState(action, null);
995
+ let text;
996
+ if (errorMsg) {
997
+ blob = errorMsg;
998
+ text = React.use(blob.text());
999
+ }
1000
+ return <form action={dispatch}>{text}</form>;
1001
+ }
1002
+
1003
+ const FormRef = await clientExports(Form);
1004
+
1005
+ const rscStream = ReactServerDOMServer.renderToReadableStream(
1006
+ <FormRef action={serverAction} />,
1007
+ webpackMap,
1008
+ );
1009
+ const response = ReactServerDOMClient.createFromReadableStream(rscStream, {
1010
+ ssrManifest: {
1011
+ moduleMap: null,
1012
+ moduleLoading: null,
1013
+ },
1014
+ });
1015
+ const ssrStream = await ReactDOMServer.renderToReadableStream(response);
1016
+ await readIntoContainer(ssrStream);
1017
+
1018
+ const form1 = container.getElementsByTagName('form')[0];
1019
+ expect(form1.textContent).toBe('');
1020
+
1021
+ async function submitTheForm() {
1022
+ const form = container.getElementsByTagName('form')[0];
1023
+ const {formState} = await submit(form);
1024
+
1025
+ // Simulate an MPA form submission by resetting the container and
1026
+ // rendering again.
1027
+ container.innerHTML = '';
1028
+
1029
+ const postbackRscStream = ReactServerDOMServer.renderToReadableStream(
1030
+ {formState, root: <FormRef action={serverAction} />},
1031
+ webpackMap,
1032
+ );
1033
+ const postbackResponse =
1034
+ await ReactServerDOMClient.createFromReadableStream(postbackRscStream, {
1035
+ ssrManifest: {
1036
+ moduleMap: null,
1037
+ moduleLoading: null,
1038
+ },
1039
+ });
1040
+ const postbackSsrStream = await ReactDOMServer.renderToReadableStream(
1041
+ postbackResponse.root,
1042
+ {formState: postbackResponse.formState},
1043
+ );
1044
+ await readIntoContainer(postbackSsrStream);
1045
+ }
1046
+
1047
+ await expect(submitTheForm).toErrorDev(
1048
+ 'Warning: Failed to serialize an action for progressive enhancement:\n' +
1049
+ 'Error: File/Blob fields are not yet supported in progressive forms. Will fallback to client hydration.',
1050
+ );
1051
+
1052
+ expect(blob instanceof Blob).toBe(true);
1053
+ expect(blob.size).toBe(2);
1054
+
1055
+ const form2 = container.getElementsByTagName('form')[0];
1056
+ expect(form2.textContent).toBe('hi');
1057
+ });
1058
});