Skip to content

Commit

Permalink
feat: support jumping to specific xblock id (openedx#1427)
Browse files Browse the repository at this point in the history
Adds ability to pass `jumpToId` query param to iframe url as id hash to
be used by browser to scroll to the correct xblock
  • Loading branch information
navinkarkera committed Sep 20, 2024
1 parent 73590f1 commit b9d1198
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 34 deletions.
3 changes: 3 additions & 0 deletions src/courseware/course/sequence/Unit/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import { useSearchParams } from 'react-router-dom';

import { AppContext } from '@edx/frontend-platform/react';
import { useIntl } from '@edx/frontend-platform/i18n';
Expand All @@ -23,6 +24,7 @@ const Unit = ({
id,
}) => {
const { formatMessage } = useIntl();
const [searchParams] = useSearchParams();
const { authenticatedUser } = React.useContext(AppContext);
const examAccess = useExamAccess({ id });
const shouldDisplayHonorCode = useShouldDisplayHonorCode({ courseId, id });
Expand All @@ -35,6 +37,7 @@ const Unit = ({
view,
format,
examAccess,
jumpToId: searchParams.get('jumpToId'),
}));

const iframeUrl = getUrl();
Expand Down
6 changes: 6 additions & 0 deletions src/courseware/course/sequence/Unit/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { when } from 'jest-when';
import { formatMessage, shallow } from '@edx/react-unit-test-utils/dist';
import { useSearchParams } from 'react-router-dom';

import { useModel } from '@src/generic/model-store';

Expand All @@ -14,6 +15,7 @@ import { modelKeys, views } from './constants';
import * as hooks from './hooks';

jest.mock('./hooks', () => ({ useUnitData: jest.fn() }));
jest.mock('react-router-dom');

jest.mock('@edx/frontend-platform/i18n', () => {
const utils = jest.requireActual('@edx/react-unit-test-utils/dist');
Expand Down Expand Up @@ -82,7 +84,11 @@ when(useModel)

let el;
describe('Unit component', () => {
const searchParams = { get: (prop) => prop };
const setSearchParams = jest.fn();

beforeEach(() => {
useSearchParams.mockImplementation(() => [searchParams, setSearchParams]);
jest.clearAllMocks();
el = shallow(<Unit {...props} />);
});
Expand Down
19 changes: 12 additions & 7 deletions src/courseware/course/sequence/Unit/urls.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getConfig } from '@edx/frontend-platform';
import { stringify } from 'query-string';
import { stringifyUrl } from 'query-string';

export const iframeParams = {
show_title: 0,
Expand All @@ -12,15 +12,20 @@ export const getIFrameUrl = ({
view,
format,
examAccess,
jumpToId,
}) => {
const xblockUrl = `${getConfig().LMS_BASE_URL}/xblock/${id}`;
const params = stringify({
...iframeParams,
view,
...(format && { format }),
...(!examAccess.blockAccess && { exam_access: examAccess.accessToken }),
return stringifyUrl({
url: xblockUrl,
query: {
...iframeParams,
view,
...(format && { format }),
...(!examAccess.blockAccess && { exam_access: examAccess.accessToken }),
jumpToId, // Pass jumpToId as query param as fragmentIdentifier is not passed to server.
},
fragmentIdentifier: jumpToId, // this is used by browser to scroll to correct block.
});
return `${xblockUrl}?${params}`;
};

export default {
Expand Down
56 changes: 29 additions & 27 deletions src/courseware/course/sequence/Unit/urls.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { getConfig } from '@edx/frontend-platform';
import { stringify } from 'query-string';
import { stringifyUrl } from 'query-string';
import { getIFrameUrl, iframeParams } from './urls';

jest.mock('@edx/frontend-platform', () => ({
getConfig: jest.fn(),
}));
jest.mock('query-string', () => ({
stringify: jest.fn((...args) => ({ stringify: args })),
stringifyUrl: jest.fn((arg) => ({ stringifyUrl: arg })),
}));

const config = { LMS_BASE_URL: 'test-lms-url' };
Expand All @@ -21,41 +21,43 @@ const props = {

describe('urls module getIFrameUrl', () => {
test('format provided, exam access and token available', () => {
const params = stringify({
...iframeParams,
view: props.view,
format: props.format,
exam_access: props.examAccess.accessToken,
const url = stringifyUrl({
url: `${config.LMS_BASE_URL}/xblock/${props.id}`,
query: {
...iframeParams,
view: props.view,
format: props.format,
exam_access: props.examAccess.accessToken,
},
});
expect(getIFrameUrl(props)).toEqual(`${config.LMS_BASE_URL}/xblock/${props.id}?${params}`);
expect(getIFrameUrl(props)).toEqual(url);
});
test('no format provided, exam access blocked', () => {
const params = stringify({ ...iframeParams, view: props.view });
const url = stringifyUrl({
url: `${config.LMS_BASE_URL}/xblock/${props.id}`,
query: { ...iframeParams, view: props.view },
});
expect(getIFrameUrl({
id: props.id,
view: props.view,
examAccess: { blockAccess: true },
})).toEqual(`${config.LMS_BASE_URL}/xblock/${props.id}?${params}`);
})).toEqual(url);
});
test('src and dest languages provided', () => {
const params = stringify({
...iframeParams,
view: props.view,
src_lang: 'test-src-lang',
dest_lang: 'test-dest-lang',
test('jumpToId and fragmentIdentifier is added to url', () => {
const url = stringifyUrl({
url: `${config.LMS_BASE_URL}/xblock/${props.id}`,
query: {
...iframeParams,
view: props.view,
format: props.format,
exam_access: props.examAccess.accessToken,
jumpToId: 'some-xblock-id',
},
fragmentIdentifier: 'some-xblock-id',
});
expect(getIFrameUrl({
...props,
srcLanguage: 'test-src-lang',
destLanguage: 'test-dest-lang',
})).toEqual(`${config.LMS_BASE_URL}/xblock/${props.id}?${params}`);
});
test('src and dest languages provided are the same', () => {
const params = stringify({ ...iframeParams, view: props.view });
expect(getIFrameUrl({
...props,
srcLanguage: 'test-lang',
destLanguage: 'test-lang',
})).toEqual(`${config.LMS_BASE_URL}/xblock/${props.id}?${params}`);
jumpToId: 'some-xblock-id',
})).toEqual(url);
});
});

0 comments on commit b9d1198

Please sign in to comment.