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:
parent
16f8e0b177
commit
a86e0e6b13
6 changed files with 163 additions and 8 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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 && (
|
||||||
|
|
80
src/apps/components/AppFrame/useUpdateAppToken.test.ts
Normal file
80
src/apps/components/AppFrame/useUpdateAppToken.test.ts
Normal 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",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
56
src/apps/components/AppFrame/useUpdateAppToken.ts
Normal file
56
src/apps/components/AppFrame/useUpdateAppToken.ts
Normal 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]);
|
||||||
|
};
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue