diff --git a/app/assets/javascripts/Components/Result/image_viewer.jsx b/app/assets/javascripts/Components/Result/image_viewer.jsx index d624e511d5..e8afc9e91f 100644 --- a/app/assets/javascripts/Components/Result/image_viewer.jsx +++ b/app/assets/javascripts/Components/Result/image_viewer.jsx @@ -188,10 +188,10 @@ export class ImageViewer extends React.PureComponent { level: Math.floor(this.state.zoom * 100), })}

diff --git a/app/assets/javascripts/Components/Result/pdf_viewer.jsx b/app/assets/javascripts/Components/Result/pdf_viewer.jsx index 80f6253fa7..fa308b0468 100644 --- a/app/assets/javascripts/Components/Result/pdf_viewer.jsx +++ b/app/assets/javascripts/Components/Result/pdf_viewer.jsx @@ -84,7 +84,10 @@ export class PDFViewer extends React.PureComponent { }; rotate = () => { - annotation_manager.rotateClockwise90(); + if (this.props.resultView) { + annotation_manager.rotateClockwise90(); + } + this.setState(({rotationInDegrees}) => ({ rotationInDegrees: (rotationInDegrees + 90) % 360, })); @@ -129,7 +132,7 @@ export class PDFViewer extends React.PureComponent { acc[value] = `${(value * 100).toFixed(0)} %`; return acc; }, - {"page-width": "Fit to page width"} + {"page-width": I18n.t("results.fit_to_page_width")} ); return valueToDisplayName; diff --git a/app/assets/javascripts/Components/__tests__/pdf_viewer.test.jsx b/app/assets/javascripts/Components/__tests__/pdf_viewer.test.jsx new file mode 100644 index 0000000000..586b38906c --- /dev/null +++ b/app/assets/javascripts/Components/__tests__/pdf_viewer.test.jsx @@ -0,0 +1,116 @@ +import React from "react"; +import {render, screen, fireEvent} from "@testing-library/react"; +import {PDFViewer} from "../Result/pdf_viewer"; + +describe("PDFViewer", () => { + let mockPdfViewer; + let mockAnnotationManager; + + beforeEach(() => { + mockPdfViewer = { + setDocument: jest.fn(), + pagesRotation: 0, + currentScaleValue: "page-width", + }; + + mockAnnotationManager = { + rotateClockwise90: jest.fn(), + }; + + global.pdfjsViewer = { + EventBus: class { + on = jest.fn(); + }, + PDFViewer: jest.fn(() => mockPdfViewer), + }; + + global.annotation_manager = mockAnnotationManager; + + render(); + }); + + afterEach(() => { + jest.restoreAllMocks(); + delete global.pdfjsViewer; + delete global.annotation_manager; + }); + + describe("rotation", () => { + let rotateButton; + + beforeEach(() => { + rotateButton = screen.getByText(I18n.t("results.rotate_image")); + }); + + it("initially has a rotation of 0", async () => { + expect(mockPdfViewer.pagesRotation).toBe(0); + }); + + it("rotates to 90 degrees when rotate button is clicked once", () => { + fireEvent.click(rotateButton); + + expect(mockAnnotationManager.rotateClockwise90).toHaveBeenCalledTimes(1); + expect(mockPdfViewer.pagesRotation).toBe(90); + }); + + it("rotates back to 0 degrees when rotate button is clicked four times", () => { + for (let i = 0; i < 4; i++) { + fireEvent.click(rotateButton); + } + + expect(mockAnnotationManager.rotateClockwise90).toHaveBeenCalledTimes(4); + expect(mockPdfViewer.pagesRotation).toBe(0); + }); + }); + + describe("zoom", () => { + it("has default zoom 'page-width' on initial render", () => { + expect(mockPdfViewer.currentScaleValue).toBe("page-width"); + }); + + it("updates zoom to 100% (1.0) when the option is selected from dropdown", () => { + const dropdown = screen.getByTestId("dropdown"); + fireEvent.click(dropdown); + + const option100 = screen.getByText("100 %"); + fireEvent.click(option100); + + expect(mockPdfViewer.currentScaleValue).toBe("1.0"); + }); + + it("updates zoom to 90% (0.9) when the option is selected from dropdown", () => { + const dropdown = screen.getByTestId("dropdown"); + fireEvent.click(dropdown); + + const option110 = screen.getByText("90 %"); + fireEvent.click(option110); + + expect(mockPdfViewer.currentScaleValue).toBe("0.9"); + }); + + it("updates zoom to 120% (1.2) when the option is selected from dropdown", () => { + const dropdown = screen.getByTestId("dropdown"); + fireEvent.click(dropdown); + + const option120 = screen.getByText("120 %"); + fireEvent.click(option120); + + expect(mockPdfViewer.currentScaleValue).toBe("1.2"); + }); + + it("resets zoom to 'page-width' when the option is selected after selecting another zoom", () => { + // set some arbitrary zoom first + const dropdown = screen.getByTestId("dropdown"); + fireEvent.click(dropdown); + const option120 = screen.getByText("120 %"); + fireEvent.click(option120); + + // now put it back to page width + fireEvent.click(dropdown); + const fitToPageWidthOption = screen.getByText(I18n.t("results.fit_to_page_width")); + fireEvent.click(fitToPageWidthOption); + + expect(mockPdfViewer.currentScaleValue).toBe("page-width"); + }); + }); +}); diff --git a/app/views/exam_templates/_student_info.html.erb b/app/views/exam_templates/_student_info.html.erb index f1ac84b126..e16efe0222 100644 --- a/app/views/exam_templates/_student_info.html.erb +++ b/app/views/exam_templates/_student_info.html.erb @@ -37,9 +37,9 @@
+ type="button" title="<%= I18n.t("results.zoom_in_image") %>"> + type="button" title="<%= I18n.t("results.zoom_out_image") %>">
diff --git a/config/locales/views/results/en.yml b/config/locales/views/results/en.yml index 0b7a3d57a2..bbb482f027 100644 --- a/config/locales/views/results/en.yml +++ b/config/locales/views/results/en.yml @@ -39,6 +39,7 @@ en: ascending: Ascending descending: Descending text_box_placeholder: Search text + fit_to_page_width: Fit to page width fullscreen_enter: Fullscreen fullscreen_exit: Leave fullscreen keybinding: @@ -92,5 +93,5 @@ en: view_token_submit: Please enter the unique token provided by your instructor to view the results for this assignment. your_mark: Your Mark zoom: 'Zoom:' - zoom_in: Zoom in - zoom_out: Zoom out + zoom_in_image: Zoom in + zoom_out_image: Zoom out