@@ -2,7 +2,6 @@ import { render, screen } from "@testing-library/react";
22import React , { act } from "react" ;
33import { Provider } from "react-redux" ;
44import { configureStore } from "@reduxjs/toolkit" ;
5- import ScratchContainer from "./ScratchContainer" ;
65import EditorReducer from "../../../redux/EditorSlice" ;
76import * as scratchIframeUtils from "../../../utils/scratchIframe" ;
87
@@ -11,6 +10,34 @@ jest.mock("../../../utils/scratchIframe", () => ({
1110 postMessageToScratchIframe : jest . fn ( ) ,
1211} ) ) ;
1312
13+ const renderMockOverlayScrollbarsComponent = ( {
14+ children,
15+ className,
16+ "data-testid" : dataTestId ,
17+ } ) => (
18+ < div className = { className } data-testid = { dataTestId } >
19+ { children }
20+ </ div >
21+ ) ;
22+
23+ const mockOverlayScrollbarsComponent = jest . fn (
24+ renderMockOverlayScrollbarsComponent ,
25+ ) ;
26+ const mockPlugin = jest . fn ( ) ;
27+
28+ jest . mock ( "overlayscrollbars-react" , ( ) => ( {
29+ OverlayScrollbarsComponent : ( props ) => mockOverlayScrollbarsComponent ( props ) ,
30+ } ) ) ;
31+
32+ jest . mock ( "overlayscrollbars" , ( ) => ( {
33+ ClickScrollPlugin : { name : "ClickScrollPlugin" } ,
34+ OverlayScrollbars : {
35+ plugin : ( ...args ) => mockPlugin ( ...args ) ,
36+ } ,
37+ } ) ) ;
38+
39+ const ScratchContainer = require ( "./ScratchContainer" ) . default ;
40+
1441describe ( "ScratchContainer" , ( ) => {
1542 const defaultEditorState = {
1643 project : {
@@ -32,13 +59,20 @@ describe("ScratchContainer", () => {
3259 } ,
3360 } ) ;
3461
35- const renderScratchContainer = ( store ) =>
62+ const renderScratchContainer = ( store = buildStore ( ) ) => {
3663 render (
3764 < Provider store = { store } >
3865 < ScratchContainer />
3966 </ Provider > ,
4067 ) ;
4168
69+ return {
70+ iframe : screen . getByTitle ( "Scratch" ) ,
71+ store,
72+ viewport : screen . getByTestId ( "scratch-container-viewport" ) ,
73+ } ;
74+ } ;
75+
4276 const dispatchMessage = ( data , origin = "https://example.com" ) => {
4377 window . dispatchEvent (
4478 new MessageEvent ( "message" , {
@@ -77,6 +111,9 @@ describe("ScratchContainer", () => {
77111 originalAssetsUrl = process . env . ASSETS_URL ;
78112 process . env . ASSETS_URL = "https://example.com" ;
79113 localStorage . clear ( ) ;
114+ mockOverlayScrollbarsComponent . mockImplementation (
115+ renderMockOverlayScrollbarsComponent ,
116+ ) ;
80117 } ) ;
81118
82119 afterEach ( ( ) => {
@@ -85,23 +122,47 @@ describe("ScratchContainer", () => {
85122 } ) ;
86123
87124 test ( "renders iframe with src built from project_id and api_url" , ( ) => {
88- const store = buildStore ( ) ;
89- renderScratchContainer ( store ) ;
125+ const { iframe, viewport } = renderScratchContainer ( ) ;
90126
91- const iframe = screen . getByTitle ( "Scratch" ) ;
127+ expect ( screen . getByTestId ( "scratch-container" ) ) . toHaveClass (
128+ "scratch-container" ,
129+ ) ;
130+ expect ( viewport ) . toHaveClass ( "scratch-container__viewport" ) ;
92131 expect ( iframe ) . toBeInTheDocument ( ) ;
132+ expect ( iframe ) . toHaveStyle ( {
133+ minWidth : "1024px" ,
134+ } ) ;
93135
94136 const url = new URL ( iframe . getAttribute ( "src" ) ) ;
95137 expect ( url . pathname ) . toBe ( "/scratch.html" ) ;
96138 expect ( url . searchParams . get ( "project_id" ) ) . toBe ( "project-123" ) ;
97139 expect ( url . searchParams . get ( "api_url" ) ) . toBe ( "https://api.example.com/v1" ) ;
98140 } ) ;
99141
100- test ( "updates the parent project identifier without reloading the iframe project_id" , async ( ) => {
101- const store = buildStore ( ) ;
102- renderScratchContainer ( store ) ;
142+ test ( "configures OverlayScrollbars for an overflow-aware horizontal Scratch scrollbar" , ( ) => {
143+ renderScratchContainer ( ) ;
103144
104- await act ( async ( ) => {
145+ expect ( mockOverlayScrollbarsComponent ) . toHaveBeenCalled ( ) ;
146+
147+ const props = mockOverlayScrollbarsComponent . mock . calls [ 0 ] [ 0 ] ;
148+
149+ expect ( props . options ) . toEqual ( {
150+ overflow : {
151+ x : "scroll" ,
152+ y : "hidden" ,
153+ } ,
154+ scrollbars : {
155+ theme : "os-theme-scratch" ,
156+ visibility : "auto" ,
157+ clickScroll : "instant" ,
158+ } ,
159+ } ) ;
160+ } ) ;
161+
162+ test ( "updates the parent project identifier without reloading the iframe project_id" , ( ) => {
163+ const { store } = renderScratchContainer ( ) ;
164+
165+ act ( ( ) => {
105166 dispatchMessage ( {
106167 type : "scratch-gui-project-id-updated" ,
107168 projectId : "project-456" ,
@@ -121,8 +182,8 @@ describe("ScratchContainer", () => {
121182 const store = buildStore ( {
122183 authReducer : ( state = { user : { access_token : "token-123" } } ) => state ,
123184 } ) ;
124- renderScratchContainer ( store ) ;
125185
186+ renderScratchContainer ( store ) ;
126187 dispatchScratchGuiReady ( { nonce : "nonce-abc" } ) ;
127188
128189 expectScratchSetTokenCall ( {
@@ -160,8 +221,8 @@ describe("ScratchContainer", () => {
160221 const store = buildStore ( {
161222 authReducer : ( state = { user : { access_token : "token-123" } } ) => state ,
162223 } ) ;
163- renderScratchContainer ( store ) ;
164224
225+ renderScratchContainer ( store ) ;
165226 dispatchScratchGuiReady ( { nonce : "nonce-1" } ) ;
166227 dispatchScratchGuiReady ( { nonce : "nonce-1" } ) ;
167228 dispatchScratchGuiReady ( { nonce : "nonce-2" } ) ;
@@ -192,6 +253,7 @@ describe("ScratchContainer", () => {
192253 user : { access_token : action . payload } ,
193254 } ;
194255 }
256+
195257 return state ;
196258 } ,
197259 } ) ;
0 commit comments