Skip to content
Merged
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
25 changes: 23 additions & 2 deletions src/components/tokenRetriever/LtiTokenRetriever.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,28 @@ describe('LtiTokenRetriever Test Suite', () => {
expect(await screen.findAllByText('Mock Child Element')).toBeDefined()
expect(mockJwtFn).toHaveBeenCalledWith(jwt, mockServer)
})


it('Does not make multiple fetch calls inside StrictMode', async () => {
const search = `?token=1234`
vi.spyOn(window, 'location', 'get').mockReturnValue({search})
mockJwtFn.mockClear()
let callCount = 0
server.use(
http.post('http://server.test/token', () => {
callCount += 1
return HttpResponse.json({jwt})
})
)
render(
<React.StrictMode>
<LtiTokenRetriever handleJwt={mockJwtFn} ltiServer={mockServer}>
<h1>Mock Child Element</h1>
</LtiTokenRetriever>
</React.StrictMode>
)
expect(await screen.findAllByText('Mock Child Element')).toBeDefined()
expect(callCount).toBe(1)
})


});
});
11 changes: 8 additions & 3 deletions src/components/tokenRetriever/LtiTokenRetriever.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Spinner } from '@instructure/ui-spinner';
import ErrorBillboard from "../errorBillboard/ErrorBillboard";

type TokenRetrieverState = {
loading: boolean
loading: boolean,
error: string | null
}

Expand All @@ -28,10 +28,15 @@ type LtiTokenRetrieverProps = {
export const LtiTokenRetriever = ({ ltiServer, handleJwt, children, location = window.location }: LtiTokenRetrieverProps) => {
const [state, setState] = useState<TokenRetrieverState>({
loading: true,
error: null
error: null,
});
// This is to prevent multiple loads of the token, especially when using <StrictMode> in development.
// A token can only be retrieved once so the second request always fails.
const hasFetchedRef = useRef(false);

useEffect(() => {
if (hasFetchedRef.current) return;
hasFetchedRef.current = true;
const fetchToken = async () => {
const token = getToken();
const server = getServer();
Expand All @@ -52,7 +57,7 @@ export const LtiTokenRetriever = ({ ltiServer, handleJwt, children, location = w

const response = await fetch(`${server}/token`, {
method: 'POST',
body: formData
body: formData,
});

if (!response.ok) {
Expand Down