Skip to content

Commit 772e525

Browse files
authored
Fix crash when subheading is clicked on ObjC page. (#951)
Example of broken flow: /documentation/foo /documentation/foo?language=objc /documentation/foo?language=objc#bar # may crash when link clicked When a user clicks a subheading link on an Objective-C variant of a page, it may crash because the renderer is mistakenly attempting to apply the patch with ObjC data a second time, which it doesn't need to. Resolves: rdar://154225522
1 parent b968b6b commit 772e525

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/views/DocumentationTopic.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ export default {
303303
},
304304
beforeRouteUpdate(to, from, next) {
305305
if (to.path === from.path && to.query.language === Language.objectiveC.key.url
306-
&& this.objcOverrides) {
306+
&& from?.query?.language !== Language.objectiveC.key.url && this.objcOverrides) {
307307
this.applyObjcOverrides();
308308
next();
309309
} else if (shouldFetchDataForRouteUpdate(to, from)) {

tests/unit/views/DocumentationTopic.spec.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,47 @@ describe('DocumentationTopic', () => {
629629
expect(next).toBeCalled();
630630
});
631631

632+
it('does not unecessarily re-apply ObjC data when navigating to fragments', () => {
633+
const oldInterfaceLang = topicData.identifier.interfaceLanguage; // swift
634+
const newInterfaceLang = 'occ';
635+
636+
const variantOverrides = [
637+
{
638+
traits: [{ interfaceLanguage: newInterfaceLang }],
639+
patch: [
640+
{ op: 'replace', path: '/identifier/interfaceLanguage', value: newInterfaceLang },
641+
// should crash if applied twice since it gets removed the first time
642+
{ op: 'remove', path: '/remoteSource' },
643+
],
644+
},
645+
];
646+
wrapper.setData({
647+
topicData: { ...topicData, variantOverrides },
648+
});
649+
expect(wrapper.vm.topicData.identifier.interfaceLanguage).toBe(oldInterfaceLang);
650+
651+
const from = mocks.$route;
652+
const to = {
653+
...from,
654+
query: { language: 'objc' },
655+
};
656+
const next = jest.fn();
657+
// there is probably a more realistic way to simulate this
658+
DocumentationTopic.beforeRouteUpdate.call(wrapper.vm, to, from, next);
659+
660+
// udpate the URL again, this time just changing the hash
661+
// this would crash if the patch mistakenly gets applied twice
662+
DocumentationTopic.beforeRouteUpdate.call(wrapper.vm, to, {
663+
...to,
664+
hash: '#abc',
665+
}, next);
666+
667+
expect(wrapper.vm.topicData.identifier.interfaceLanguage).not.toBe(oldInterfaceLang);
668+
expect(wrapper.vm.topicData.identifier.interfaceLanguage).toBe(newInterfaceLang);
669+
expect(routeEnterMock).not.toBeCalled();
670+
expect(next).toBeCalled();
671+
});
672+
632673
it('skips fetching data, if `meta.skipFetchingData` is `true`', () => {
633674
const next = jest.fn();
634675
DocumentationTopic.beforeRouteEnter({ meta: { skipFetchingData: true } }, {}, next);

0 commit comments

Comments
 (0)