Add hook that sends updated app token to the App (#3683)

* Add hook that sends updated app token to the App

* Install latest app-sdk@0.39.1
This commit is contained in:
Lukasz Ostrowski 2023-05-25 15:35:17 +02:00 committed by GitHub
parent 16f8e0b177
commit a86e0e6b13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 163 additions and 8 deletions

14
package-lock.json generated
View file

@ -116,7 +116,7 @@
"@percy/cli": "^1.21.0", "@percy/cli": "^1.21.0",
"@percy/cypress": "^3.1.2", "@percy/cypress": "^3.1.2",
"@release-it/bumper": "^2.0.0", "@release-it/bumper": "^2.0.0",
"@saleor/app-sdk": "0.37.3", "@saleor/app-sdk": "0.39.1",
"@types/apollo-upload-client": "^17.0.2", "@types/apollo-upload-client": "^17.0.2",
"@types/color-convert": "^2.0.0", "@types/color-convert": "^2.0.0",
"@types/debug": "^4.1.7", "@types/debug": "^4.1.7",
@ -7913,9 +7913,9 @@
} }
}, },
"node_modules/@saleor/app-sdk": { "node_modules/@saleor/app-sdk": {
"version": "0.37.3", "version": "0.39.1",
"resolved": "https://registry.npmjs.org/@saleor/app-sdk/-/app-sdk-0.37.3.tgz", "resolved": "https://registry.npmjs.org/@saleor/app-sdk/-/app-sdk-0.39.1.tgz",
"integrity": "sha512-DFAjiEFBFIDWDqZvaXar8860zDgSZih2n7gT3e+aOpLIfnmMZ0nL6+aNS3A7ym2IStx8oUoPI1RFZBIeuF9+hg==", "integrity": "sha512-PBREZWwkk+DHCBhOZzsuFdp7/vLItxfAqKD+gcZ5QxzSAt82S0/FS6ii7igpW3H+bEiK4oBUjMxgUyhJMOXQHw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@changesets/cli": "^2.26.0", "@changesets/cli": "^2.26.0",
@ -41291,9 +41291,9 @@
} }
}, },
"@saleor/app-sdk": { "@saleor/app-sdk": {
"version": "0.37.3", "version": "0.39.1",
"resolved": "https://registry.npmjs.org/@saleor/app-sdk/-/app-sdk-0.37.3.tgz", "resolved": "https://registry.npmjs.org/@saleor/app-sdk/-/app-sdk-0.39.1.tgz",
"integrity": "sha512-DFAjiEFBFIDWDqZvaXar8860zDgSZih2n7gT3e+aOpLIfnmMZ0nL6+aNS3A7ym2IStx8oUoPI1RFZBIeuF9+hg==", "integrity": "sha512-PBREZWwkk+DHCBhOZzsuFdp7/vLItxfAqKD+gcZ5QxzSAt82S0/FS6ii7igpW3H+bEiK4oBUjMxgUyhJMOXQHw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@changesets/cli": "^2.26.0", "@changesets/cli": "^2.26.0",

View file

@ -123,7 +123,7 @@
"@percy/cli": "^1.21.0", "@percy/cli": "^1.21.0",
"@percy/cypress": "^3.1.2", "@percy/cypress": "^3.1.2",
"@release-it/bumper": "^2.0.0", "@release-it/bumper": "^2.0.0",
"@saleor/app-sdk": "0.37.3", "@saleor/app-sdk": "0.39.1",
"@types/apollo-upload-client": "^17.0.2", "@types/apollo-upload-client": "^17.0.2",
"@types/color-convert": "^2.0.0", "@types/color-convert": "^2.0.0",
"@types/debug": "^4.1.7", "@types/debug": "^4.1.7",

View file

@ -1,4 +1,5 @@
import { useAppDashboardUpdates } from "@dashboard/apps/components/AppFrame/useAppDashboardUpdates"; import { useAppDashboardUpdates } from "@dashboard/apps/components/AppFrame/useAppDashboardUpdates";
import { useUpdateAppToken } from "@dashboard/apps/components/AppFrame/useUpdateAppToken";
import { import {
AppDetailsUrlQueryParams, AppDetailsUrlQueryParams,
prepareFeatureFlagsList, prepareFeatureFlagsList,
@ -76,6 +77,15 @@ export const AppFrame: React.FC<Props> = ({
const featureFlags = useMemo(() => prepareFeatureFlagsList(flags), [flags]); const featureFlags = useMemo(() => prepareFeatureFlagsList(flags), [flags]);
useUpdateAppToken({
postToExtension,
appToken,
/**
* If app is not ready, ignore this flow
*/
enabled: handshakeDone,
});
return ( return (
<> <>
{!handshakeDone && ( {!handshakeDone && (

View file

@ -0,0 +1,80 @@
import { useUpdateAppToken } from "@dashboard/apps/components/AppFrame/useUpdateAppToken";
import { renderHook } from "@testing-library/react-hooks";
describe("useUpdateAppToken", function () {
const postMessage = jest.fn();
beforeEach(() => {
jest.resetAllMocks();
});
it("Doesnt do anything if disabled", () => {
const { waitFor } = renderHook(props => useUpdateAppToken(props), {
initialProps: {
enabled: true,
appToken: "initialToken",
postToExtension: postMessage,
},
});
return waitFor(() => {
expect(postMessage).not.toHaveBeenCalled();
});
});
it("Doesnt do anything if re-rendered, but token stays the same between renders", () => {
const localPostMessage = jest.fn();
const { rerender, waitFor } = renderHook(
props => useUpdateAppToken(props),
{
initialProps: {
enabled: true,
appToken: "initialToken",
postToExtension: postMessage,
},
},
);
rerender({
enabled: true,
appToken: "initialToken",
// simulate props change due to reference change
postToExtension: localPostMessage,
});
return waitFor(() => {
expect(postMessage).not.toHaveBeenCalled();
expect(localPostMessage).not.toHaveBeenCalled();
});
});
it("Calls postMessage if token changes in props and enabled", async () => {
const { rerender, waitFor } = renderHook(
props => useUpdateAppToken(props),
{
initialProps: {
enabled: true,
appToken: "initialToken",
postToExtension: postMessage,
},
},
);
rerender({
enabled: true,
appToken: "updatedToken",
// simulate props change due to reference change
postToExtension: postMessage,
});
return waitFor(() => {
expect(postMessage).toHaveBeenCalledWith({
type: "tokenRefresh",
payload: {
token: "updatedToken",
},
});
});
});
});

View file

@ -0,0 +1,56 @@
import { createAppsDebug } from "@dashboard/apps/apps-debug";
import { DashboardEventFactory, Events } from "@saleor/app-sdk/app-bridge";
import { useEffect, useRef } from "react";
/**
* https://usehooks.com/usePrevious/
*/
function usePreviousValue(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
interface Args {
enabled: boolean;
appToken: string;
postToExtension: (events: Events) => void;
}
const debug = createAppsDebug("useUpdateAppToken");
/**
* Listens on appToken changes and pushes it to the App if changed.
*/
export const useUpdateAppToken = ({
enabled,
appToken,
postToExtension,
}: Args) => {
const cachedToken = usePreviousValue(appToken);
useEffect(() => {
if (!enabled) {
return;
}
if (!cachedToken) {
/**
* Missing cache token means its first render, so we dont want to send it to app
*/
return;
}
if (cachedToken !== appToken) {
debug("Will send new token to the app");
/**
* Ensure running only when token changes. If token changes, send it to app
*/
postToExtension(DashboardEventFactory.createTokenRefreshEvent(appToken));
}
}, [enabled, appToken, cachedToken, postToExtension]);
};

View file

@ -31,3 +31,12 @@ window.__SALEOR_CONFIG__ = {
process.env.TZ = "UTC"; process.env.TZ = "UTC";
configure({ testIdAttribute: "data-test-id" }); configure({ testIdAttribute: "data-test-id" });
/**
* https://github.com/inrupt/solid-client-authn-js/issues/1676
*
* Fixes (hacks) "TextEncoder is not defined" error which is likely bug in jsdom
*/
import { TextDecoder, TextEncoder } from "util";
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;