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
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"parserOptions": {
"ecmaFeatures": { "jsx": true },
"sourceType": "module",
"project": "./tsconfig.json"
"project": ["./tsconfig.json", "./tests/js/tsconfig.json"]
},
"plugins": ["@typescript-eslint"],
"rules": {
Expand Down
43 changes: 19 additions & 24 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,22 @@ jobs:
- name: Build Plugin ZIP
run: make zip

- name: Create Release and Upload Asset
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ steps.get_version.outputs.VERSION }}
name: v${{ steps.get_version.outputs.VERSION }}
generate_release_notes: true
files: carousel-kit.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Prepare Distribution Bundle
run: |
mkdir dist-bundle
cp carousel-kit.zip dist-bundle/

- name: Deploy to Dist Branch
uses: s0/git-publish-subdir-action@develop
env:
REPO: self
BRANCH: dist
FOLDER: dist-bundle
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MESSAGE: "chore: distribution build v${{ steps.get_version.outputs.VERSION }}"
SKIP_EMPTY_COMMITS: true
- name: Create Release and Upload Asset

uses: softprops/action-gh-release@v1

with:

tag_name: v${{ steps.get_version.outputs.VERSION }}

name: v${{ steps.get_version.outputs.VERSION }}

generate_release_notes: true

files: core-carousel.zip

env:

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


5 changes: 2 additions & 3 deletions blueprint.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
"step": "installPlugin",
"pluginData": {
"resource": "url",
"url": "https://cdn.statically.io/gh/rtCamp/carousel-kit@dist/carousel-kit.zip"
"url": "https://github.com/rtCamp/core-carousel/releases/latest/download/core-carousel.zip"
}
},
{
"step": "login",
"username": "admin",
"password": "password"
"username": "admin"
},
{
"step": "importWxr",
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"devDependencies": {
"@commitlint/cli": "20.4.1",
"@commitlint/config-conventional": "20.4.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "^16.1.0",
"@types/jest": "^29.5.14",
"@types/react": "^18.3.27",
Expand All @@ -63,4 +63,4 @@
"react-dom": "^18.3.1",
"webpack-dev-server": ">=5.2.1"
}
}
}
91 changes: 42 additions & 49 deletions src/blocks/carousel/__tests__/view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@
* @package
*/

import {
store,
getContext,
getElement,
} from '@wordpress/interactivity';
import { store, getContext, getElement } from '@wordpress/interactivity';

import EmblaCarousel, { type EmblaCarouselType } from 'embla-carousel';

Expand All @@ -25,7 +21,7 @@ const EMBLA_KEY = Symbol.for( 'carousel-kit.carousel' );

// Type for viewport element with Embla instance attached
type EmblaViewportElement = HTMLElement & {
[ EMBLA_KEY ]?: EmblaCarouselType;
[EMBLA_KEY]?: EmblaCarouselType;
};

import type { CarouselContext } from '../types';
Expand All @@ -41,23 +37,25 @@ const storeConfig = storeCall ? storeCall[ 1 ] : null;

/**
* Helper to set Embla instance on a viewport element.
* @param viewport The viewport element to attach the Embla instance to.
* @param embla The Embla instance to attach.
*
* @param {HTMLElement} viewport The viewport element to attach the Embla instance to.
* @param {Partial<EmblaCarouselType>} embla The Embla instance to attach.
*/
const setEmblaOnViewport = (
viewport: HTMLElement,
embla: Partial< EmblaCarouselType >,
embla: Partial<EmblaCarouselType>,
) => {
( viewport as EmblaViewportElement )[ EMBLA_KEY ] =
embla as EmblaCarouselType;
( viewport as EmblaViewportElement )[ EMBLA_KEY ] = embla as EmblaCarouselType;
};

/**
* Helper to create mock carousel context with customizable properties.
* @param overrides Partial properties to override in the default context.
*
* @param {Partial<CarouselContext>} overrides Partial properties to override in the default context.
* @return {CarouselContext} The mock carousel context.
*/
const createMockContext = (
overrides: Partial< CarouselContext > = {},
overrides: Partial<CarouselContext> = {},
): CarouselContext => ( {
options: { loop: true },
autoplay: false,
Expand All @@ -73,6 +71,8 @@ const createMockContext = (

/**
* Helper to create a mock DOM element structure for carousel.
*
* @return {Object} The mock DOM elements.
*/
const createMockCarouselDOM = () => {
const viewport = document.createElement( 'div' );
Expand All @@ -90,7 +90,9 @@ const createMockCarouselDOM = () => {

/**
* Helper to create mock Embla instance with all required methods.
* @param overrides Partial methods to override in the default mock instance.
*
* @param {Object} overrides Partial methods to override in the default mock instance.
* @return {Object} The mock Embla instance.
*/
const createMockEmblaInstance = ( overrides = {} ) => ( {
scrollPrev: jest.fn(),
Expand Down Expand Up @@ -227,9 +229,7 @@ describe( 'Carousel View Module', () => {
} );

it( 'should log warning when embla instance not found', () => {
const consoleSpy = jest
.spyOn( console, 'warn' )
.mockImplementation();
const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation();
const button = document.createElement( 'button' );

( getElement as jest.Mock ).mockReturnValue( { ref: button } );
Expand All @@ -244,9 +244,7 @@ describe( 'Carousel View Module', () => {
} );

it( 'should handle null element gracefully', () => {
const consoleSpy = jest
.spyOn( console, 'warn' )
.mockImplementation();
const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation();
( getElement as jest.Mock ).mockReturnValue( null );

expect( () => storeConfig.actions.scrollPrev() ).not.toThrow();
Expand Down Expand Up @@ -279,9 +277,7 @@ describe( 'Carousel View Module', () => {
} );

it( 'should log warning when embla instance not found', () => {
const consoleSpy = jest
.spyOn( console, 'warn' )
.mockImplementation();
const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation();
const button = document.createElement( 'button' );

( getElement as jest.Mock ).mockReturnValue( { ref: button } );
Expand Down Expand Up @@ -309,8 +305,9 @@ describe( 'Carousel View Module', () => {
setEmblaOnViewport( viewport, mockEmbla );

const mockContext = createMockContext();
( mockContext as CarouselContext & { snap?: { index: number } } ).snap =
{ index: 2 };
( mockContext as CarouselContext & { snap?: { index: number } } ).snap = {
index: 2,
};

( getContext as jest.Mock ).mockReturnValue( mockContext );
( getElement as jest.Mock ).mockReturnValue( { ref: button } );
Expand Down Expand Up @@ -338,8 +335,9 @@ describe( 'Carousel View Module', () => {
setEmblaOnViewport( viewport, mockEmbla );

const mockContext = createMockContext();
( mockContext as CarouselContext & { snap?: { index: number } } ).snap =
{ index: 0 };
( mockContext as CarouselContext & { snap?: { index: number } } ).snap = {
index: 0,
};

( getContext as jest.Mock ).mockReturnValue( mockContext );
( getElement as jest.Mock ).mockReturnValue( { ref: button } );
Expand All @@ -362,9 +360,7 @@ describe( 'Carousel View Module', () => {
describe( 'isSlideActive', () => {
it( 'should be defined as a function', () => {
expect( storeConfig?.callbacks?.isSlideActive ).toBeDefined();
expect( typeof storeConfig?.callbacks?.isSlideActive ).toBe(
'function',
);
expect( typeof storeConfig?.callbacks?.isSlideActive ).toBe( 'function' );
} );

it( 'should return false when element is null', () => {
Expand Down Expand Up @@ -446,8 +442,9 @@ describe( 'Carousel View Module', () => {

it( 'should return true when snap.index matches selectedIndex', () => {
const mockContext = createMockContext( { selectedIndex: 2 } );
( mockContext as CarouselContext & { snap?: { index: number } } ).snap =
{ index: 2 };
( mockContext as CarouselContext & { snap?: { index: number } } ).snap = {
index: 2,
};

( getContext as jest.Mock ).mockReturnValue( mockContext );

Expand All @@ -458,8 +455,9 @@ describe( 'Carousel View Module', () => {

it( 'should return false when snap.index does not match selectedIndex', () => {
const mockContext = createMockContext( { selectedIndex: 0 } );
( mockContext as CarouselContext & { snap?: { index: number } } ).snap =
{ index: 2 };
( mockContext as CarouselContext & { snap?: { index: number } } ).snap = {
index: 2,
};

( getContext as jest.Mock ).mockReturnValue( mockContext );

Expand All @@ -479,8 +477,9 @@ describe( 'Carousel View Module', () => {
const mockContext = createMockContext( {
ariaLabelPattern: 'Go to slide %d',
} );
( mockContext as CarouselContext & { snap?: { index: number } } ).snap =
{ index: 2 };
( mockContext as CarouselContext & { snap?: { index: number } } ).snap = {
index: 2,
};

( getContext as jest.Mock ).mockReturnValue( mockContext );

Expand All @@ -493,8 +492,9 @@ describe( 'Carousel View Module', () => {
const mockContext = createMockContext( {
ariaLabelPattern: 'Slide %d of 5',
} );
( mockContext as CarouselContext & { snap?: { index: number } } ).snap =
{ index: 0 };
( mockContext as CarouselContext & { snap?: { index: number } } ).snap = {
index: 0,
};

( getContext as jest.Mock ).mockReturnValue( mockContext );

Expand All @@ -519,15 +519,11 @@ describe( 'Carousel View Module', () => {
describe( 'initCarousel', () => {
it( 'should be defined as a function', () => {
expect( storeConfig?.callbacks?.initCarousel ).toBeDefined();
expect( typeof storeConfig?.callbacks?.initCarousel ).toBe(
'function',
);
expect( typeof storeConfig?.callbacks?.initCarousel ).toBe( 'function' );
} );

it( 'should return early and log warning for invalid element', () => {
const consoleSpy = jest
.spyOn( console, 'warn' )
.mockImplementation();
const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation();
const mockContext = createMockContext();

( getContext as jest.Mock ).mockReturnValue( mockContext );
Expand All @@ -545,9 +541,7 @@ describe( 'Carousel View Module', () => {
} );

it( 'should log warning when viewport not found', () => {
const consoleSpy = jest
.spyOn( console, 'warn' )
.mockImplementation();
const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation();
const mockContext = createMockContext();
const element = document.createElement( 'div' );

Expand Down Expand Up @@ -596,8 +590,7 @@ describe( 'Carousel View Module', () => {

describe( 'Embla Carousel Integration', () => {
// Type-safe helper to get mocked Embla instance
const getMockedEmblaCarousel = () =>
EmblaCarousel as unknown as jest.Mock;
const getMockedEmblaCarousel = () => EmblaCarousel as unknown as jest.Mock;

it( 'should have EmblaCarousel mocked', () => {
expect( EmblaCarousel ).toBeDefined();
Expand Down