Jump to content
Search Community

How to setup Vitest Unit Testing for Timeline Duration

Christopher DuCharme test
Moderator Tag

Recommended Posts

I have recently switched over from Gulp to Vite for building banners and now exploring Unit Tests for the first time.

 

For example, I would like to create a unit test that checks the duration of the timeline to make sure it does not exceed 15 seconds max animation per banner specs.

 

I was hoping it would be as simple as adding the following code in my timeline file to export the timeline length:

const duration = tl.endTime()
export { duration as duration }

Then import duration into my test file and run the following test.

test('Timeline should not exceed 15 seconds', () => {
    expect(duration).toBeLessThanOrEqual(15);
})

However, the test then fails with

ReferenceError: gsap is not defined

What is the proper way to configure a export and import to test a gsap timeline?

 

I'm new to unit testing so any help with how to set up a proper working test to get me started would be greatly appreciated.

 

 

 

 

 

 

Link to comment
Share on other sites

Hi @Christopher DuCharme. It's hard to troubleshoot based on the limited information you're providing, but I did want to point out that tl.endTime() probably is NOT what you want. Would you want to test tl.duration()? The endTime() refers to the time relative to the PARENT timeline's playhead. 

 

Your error indicates gsap isn't defined, but none of the code you shared even references GSAP, so I'm not sure what's going on in your files, sorry. Maybe you just have to import gsap. 

Link to comment
Share on other sites

Thanks for the reply @GreenSock

 

The NDA we have with our clients prevents us from posting any actual code examples, but I just took the type to make a generic reproduction of the timeline and test.

This is the timeline.js file:

 

import ScrollToPlugin from "./greensock/ScrollToPlugin.js"

gsap.registerPlugin(ScrollToPlugin)
gsap.config({ autoKillThreshold: 2 })
const tl = new gsap.timeline({ repeat: 0, repeatDelay: 2.5 })
const easeOut = Power2.easeOut
const isi = new gsap.timeline({ repeat: 0, delay: 15 })
const max = ScrollToPlugin.max(document.querySelector('#isi'), 'y')

tl.to('.frame1', {alpha: 1, duration: 0.5, delay:0.25})
tl.to('.gradient, .frame1', {alpha:0, duration: 0.5, delay:2.5}, ">")
tl.to('.gradient-2', {alpha:1, scale: 1, duration: 0.5, ease:easeOut}, "<")
tl.to('.person1, .bg1', {alpha:1, duration: 0.5}, "<")
tl.to('.person2', {alpha:1, duration: 0.5}, ">")
tl.to('.person1, .bg2, .frame2', {alpha:0, duration: 0.5, delay:2.75}, ">")
tl.to('.person2, .bg2', {alpha:1, duration: 0.5}, "<")
tl.to('.person3', {alpha:1, duration: 0.5}, ">")
tl.to('.person2, .bg3, .frame3', {alpha:0, duration: 0.5, delay:2.75}, ">")
tl.to('.person3, .bg3', {alpha:1, duration: 0.5}, "<")
tl.to('.frame4', {alpha:1, duration: 0.5}, ">")
tl.to('.cta', {alpha:1, duration: 0.5}, ">")

console.log('Timeline duration: ' + tl.duration())
const duration = tl.duration()
export { duration as duration }

document.addEventListener("DOMContentLoaded", () => {
    const isi = new gsap.timeline({ repeat: 0, delay: 15 })
    let max = 0
    function loadTimer() {
        max = ScrollToPlugin.max(document.querySelector('#isi'), 'y')
        console.log('ISI Height: ' + max + 'px')

        isi.to(
            '#isi',
            {
                duration: 90,
                scrollTo: { y: max, autoKill: true },
                ease: 'none',
            },
        )
    }
    setTimeout(loadTimer, 2000)
});

This is my vitest.config.ts file:

 

import { defineConfig } from 'vitest/config'

export default defineConfig({
    test: {
        reporters: ['html'],
        include: ['concept-1/**/test/*.{js,ts}'],
    },
})

And this the test file.

import { assert, expect, test } from 'vitest'
import { duration } from '../javascript/timeline.js'

// Edit an assertion and save to see HMR in action

test('Timeline should not exceed 15 seconds', () => {
    expect(duration).toBeLessThanOrEqual(15);
})

 

GSAP is defined / loaded in the index.html loading from the DoubleClick CDN, and not my javascript / modules.  So I have a feeling that is the issue.  GSAP is defined for the banners themselves but not the test itself. Importing gsap to the timeline.js file resolves gsap not being defines and next moves on to the easing not being defined.

 

I was using the DoubleClick CDN because the file weight of gsap is exempt. Key when you have 200k max. But I'm wondering using the modular approach importing only what I need from GreenSock is what I need to be doing to get this to work.

 

 

Link to comment
Share on other sites

You forgot to import the Power2 class that you're using for easing. But actually I would strongly recommend shifting to the more modern string-based syntax - you're using the VERY old v2 syntax: 

// old
ease: Power2.easeOut

// new
ease: "power2.out"

And yeah, it sounds like you've gotta import the GSAP-related tools in your files. You're probably used to just loading the minified files via a standard <script> tag, but your testing environment looks to be NPM-based, so you do imports of modules instead. That's totally doable with GSAP, of course. Just install the "gsap" package and add your imports. https://greensock.com/install

  • Like 2
Link to comment
Share on other sites

Thanks for the heads up on the old syntax. Just fixed.

 

I think I'm mostly there now. I have the banner fully running in the browser using imported modules.  However I'm still getting an error with the test.  I'm assuming error is related to the dom elements not being defined. To resolve this, would you make mock elements in the test or import the dom somehow?

 

TypeError: Cannot read properties of undefined (reading 'querySelectorAll')
    at toArray (/Users/christopherducharme/Documents/project/node_modules/gsap/dist/gsap.js:640:175)
    at new Tween (/Users/christopherducharme/Documents/project/node_modules/gsap/dist/gsap.js:2962:130)
    at _createTweenType (/Users/christopherducharme/Documents/project/node_modules/gsap/dist/gsap.js:608:12)
    at Timeline.to (/Users/christopherducharme/Documents/project/node_modules/gsap/dist/gsap.js:1898:7)

 

Link to comment
Share on other sites

Hi,

 

Indeed the issue is that there are no DOM elements. I don't know much about unit testing and of the few things I've done certainly don't include testing the duration of a GSAP Timeline. The reason is that GSAP should be responsible for doing that testing for you, but I understand that sometimes teams do that.

 

With that in mind I don't know enough about Vitest, but the few things I've done I used Testing Library since it allows you to test directly on the same HTML your app is actually using. IDK if Vitest can be integrated with that or not. I assume that you are actually testing production code and not mock code like code in a specific test file that is not used on production. If you can mock the DOM elements then, yeah do that. If you can't then you can mock objects with the properties you are testing or just use empty objects to just assert the duration of the timeline:

const tl = gsap.timeline();

tl
  .to({}, {duration: 1})
  .to({}, {duration: 2})
  .to({}, {duration: 0.5})
  .to({}, {duration: 0.17});
// Duration should be 3.67

If you want to can add the properties you want to tween in the dummy objects as well, if you need to assert the final values after the GSAP Timeline has completed.

 

Sorry I can't be of more assistance. Let us know if you have more questions.

 

Happy Tweening!

Link to comment
Share on other sites

Yep, it sounds like you're trying to run the GSAP tests in a SSR (server side rendering) environment where there's no "document" at all. That's obviously not gonna work if you're trying to use selector text for your animation targets (there's literally no document or elements). So you'll have to run your tests in a way that allows the document/window to be defined. That's not really something I can help you with. 

 

For me personally, I run tests directly in the browser - I string together function calls where each function does a specific test and then if there are errors, I log them to the console, etc. So I just open the test page in my browser and wait for the tests to finish and look at the console. Old school. Love it. :)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...