cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.5k stars 3.15k forks source link

Feature request: High-level way to assert whether the browser is playing an audio file #1750

Closed nwshane closed 5 years ago

nwshane commented 6 years ago

Current behavior:

No high-level ability to test whether the browser is playing an audio file.

Desired behavior:

If possible, it'd be great to have a high-level way to check whether a specific audio file is currently being played by the browser, whether by an <audio> tag, the web audio API, or some other method that I don't know about.

This could be something like cy.audio('https://example.com/path/to/music/file.mp3').should('be.playing').

My app uses howler JS to play audio files, and all I've been able to come up with in terms of testing the music is to use cy.window() to access the Howler global. This works okay, but it'd be great if there was a better way to do this that wasn't so tied to the specific tool I'm using.

nwshane commented 6 years ago

Whenever a Chrome tab is playing music, it shows a little music icon next to the X tab button:

tab music icon

This makes me think that there must be a way of programmatically asking the browser, "Is this tab playing music?" and gives me hope that this should be possible to do (at least from the browser's perspective).

kuceb commented 6 years ago

@nwshane you can use this if you want to ensure audio is playing for the client....if you we're using audio or video elements.

const expectPlayingAudio = () => {
  cy.get('audio,video').should((els)=>{
    let audible = false
    els.each((i, el)=>{
      console.log(el)
      console.log(el.duration, el.paused, el.muted)
      if (el.duration > 0 && !el.paused && !el.muted) {
        audible = true
      }

      // expect(el.duration > 0 && !el.paused && !el.muted).to.eq(false)
    })
    expect(audible).to.eq(true)
  })
}

describe('page', () => {
  it('works', () => {
    cy.visit('/')
    expectPlayingAudio()
  })
})
nwshane commented 6 years ago

@Bkucera Thanks for the response! I'm playing the songs with howler JS though, so there's no audio element in the DOM.

kuceb commented 6 years ago

@nwshane you can try stubbing the window.Audio contructor, which Howler uses. That way you can get access to the same elements that howlerjs is using:

    const audios = []

    cy.visit('/', {onBeforeLoad: (win)=> {
      const originalAudio = win.Audio
      cy.stub(win, 'Audio').callsFake(()=>{
        const aud = new originalAudio()
        audios.push(aud)
        return aud
      })
    }})

    cy.wrap(null).should(() => {
      audios.forEach(aud => {
        console.log(aud.paused, aud.muted)
        expect(aud.paused || aud.muted).eq(true)
      })
    })
jennifer-shehane commented 5 years ago

@nwshane Were you able to get this to work?

jennifer-shehane commented 5 years ago

Unfortunately we have to close this issue due to inactivity. Please comment if there is new information to provide concerning the original issue and we can reopen.

mwren-mshanken commented 4 years ago

I was able to get this example working for a video player with some modification.

It would have been nice to have asserts and commands that do something similar to work with out of the box:

cy.get('video')
.playVideo()
.should('be.playingVideo')

For now this can be done with custom commands, but I think that these would be nice additions for some people.

dyc3 commented 3 years ago

The solutions in this thread do not work if the audio is coming from an iframe, like the youtube embedded iframe player.

jennifer-shehane commented 3 years ago

@dyc3 Yah, likely a part of our larger work on iframe support which we're working on. https://github.com/cypress-io/cypress/issues/136

ghost commented 3 years ago

I think we can approach the same problem with test harnesses as well, I opened an issue for that: https://github.com/goldfire/howler.js/issues/1486 .

andrewagain commented 2 years ago

The above methods are difficult when using AudioContext / AudioBufferSourceNode. Plus, I would love my tests to be less implementation specific. If I change how my audio gets played, i shouldn't have to rewrite my tests.

Chrome extensions can check if audio is playing. Is Cypress able to access extension APIs?

https://stackoverflow.com/a/41651398/749458

https://developer.chrome.com/docs/extensions/reference/tabs/ (search for "audible")

distante commented 2 years ago

I am really interested in this although maybe my use case is a little bit more complex.

I need to be able to test changes in the sound itself. Like, be able to take some kind of audio snapshot and compare it to another.

Take this old web app as an example: https://www.saninnsalas.com/coding/audio-training/. When changing the config the same sound (frequency) is played but with another gain. Being able to test take would be really good.

benwiley4000 commented 2 years ago

Like @ahfarmer I'm interested in this for detecting playback via the Web Audio API. Seems like the extension API would be a good lead.

illright commented 2 years ago

@jennifer-shehane Could we reopen this? Seems like a valid feature request that is still not implemented

mikelhamer commented 1 year ago

yes please