Showing posts with label reelbjj. Show all posts
Showing posts with label reelbjj. Show all posts

Monday, April 05, 2021

Reel BJJ Public Beta is live!

I'm super excited to have opened up the web application version of Reel BJJ for public Beta feedback. Reel BJJ is a video management application for athletes and coaches who want to get the most out of their Brazilian jiu-jitsu videos. (Try it now--there's a free trial.)

Reel BJJ logo

Why create a jiu-jitsu video app? The answer is simple. There is an amazing library of jiu-jitsu content available from a number of sites such as BJJ Fanatics, GrappleArts, Grapplers Guide, BJJ Library, and Gracie University--the list goes on. In fact, in a recent interview with Bernardo Faria on BJJ Fanatics, Mikey Muscimeci made exactly this point. The content available to people wanting to learn techniques is seemingly endless. However, the way video is used for learning jiu-jitsu hasn't changed--most people just watch an instructional through and hope they remember the best parts. The mission of Reel BJJ is to change the way people think about learning jiu-jitsu via video.



- Reel BJJ allows users to create Reels without video editing

In short, Reel BJJ can help everyone (athletes, instructors, coaches, or hobbyists) get the most value possible from video content. The first main feature of the Reel BJJ Beta release is called Reels (and before anyone gets upset with me, I created Reels a while back, so yes, it was before Instagram stole my thunder). Reels allow anyone to quickly (and easily) create highlights from their jiu-jitsu videos and then just watch the parts of the videos they want to review. (You can see how Reels work in this short walkthrough video of the Reel BJJ Beta.)

Some of the most common scenarios for Reels would include:

  • Techniques you'd like to learn
  • Techniques you'd like to try before class
  • Review footage of your sparring rounds
  • Review footage of your competition matches
  • Researching opponents for upcoming competitions
  • Creating a game plan of techniques

The key, of course, is that Reel BJJ users can do this without any software install or video editing. Users can add videos from YouTube, Vimeo, or even upload their own videos, and then create highlights. Naturally, you'll want to add notes to your highlights, so Reel BJJ has a cool notes features that was just shipped.

Reel BJJ Beta Notes

It's important to note that Reel BJJ does not download videos from streaming services, or violate their terms of service in any way. The videos remain at the source and aren't altered in any way.

I'm excited to see what will happen. The Beta feedback so far has been fantastic. For example, here's some feedback from Thomas Lisboa.

"It's unbelievable how jiu-jitsu is constantly evolving. That's why I was so excited when I discovered Reel BJJ. I can select the parts I liked most in a course and review them. For those who like to study jiu-jitsu, regardless of their level and goals, Reel BJJ is the evolution of jiu-jitsu study." - Thomas Lisboa (Head Coach of Alliance BJJ Vancouver)


Tuesday, October 27, 2020

Cypress.io testing with Auth0 and Angular 10

I read the documentation on both the Auth0 site and the Cypress.io site about using the two technologies together with the Angular framework, but I simply couldn't get it to work.

For example, the tutorial on the Auth0 Blog called The Complete Guide to Angular User Authentication with Auth0 got me most of the way there and the same was true for the Cypress.io "real-world app" code and documentation on GitHub (which is written for React BTW).

These two resources (plus some community posts) allowed me to set up all the underpinnings of a working test system but didn't resolve all my issues. In the past, my Angular project exclusively used Google Authentication, so my Cypress tests required me manually login first, and then run all the tests that needed an authenticated user. It wasn't perfect, but it was workable. However, his manual login option did not work with Auth0 (and Angular 10). Google Authentication would not allow the login window to open in an iFrame when running in the context of a Cypress test (i.e., Cypress was automating/controlling the browser).

- Auth0 authenticated tests running successfully in Cypress.io and Angular 10


This is what I ultimately did to get it working:

1.  Switch my Node.js API from Google tokens to Auth0 authentication tokens by following the Auth0 quickstart for Node.js (Express) backends.

2. Set up a test SPA Application in Auth0 with lower security than my production app. This allowed me to enable username/password logins and turn on the Password Grant Types (under Application > Advanced Settings).

3. Follow the Cypress real-world app section called "Cypress Setup for Testing Auth0) to add a Login function to my Cypress.io setup.

Under Cypress > support > commands.ts, I now have the code below. You can also use plain JavaScript of course. The configuration for the variables is found under src > cypress.env.json.

/// <reference types="cypress" />

/// <reference types="jwt-decode" />

import jwt_decode from 'jwt-decode';


Cypress.Commands.add('login', (overrides = {}) => {

  const username = Cypress.env('auth0_username');

  cy.log(`Logging in as ${username}`);

    cy.request({

      method: "POST",

      url: Cypress.env('auth0_url'),

      body: {

        grant_type: 'password',

        username: Cypress.env('auth0_username'),

        password: Cypress.env('auth0_password'),

        audience: Cypress.env('auth0_audience'),

        scope: Cypress.env('auth0_scope'),

        client_id: Cypress.env('auth0_client_id'),

        client_secret: Cypress.env('auth0_client_secret'),  

      },

    }).then(({ body }) => {

      const claims: any = jwt_decode(body.id_token);

      const { nickname, name, picture, updated_at, email, email_verified, sub, exp } = claims;


      const item = {

        body: {

          ...body,

          decodedToken: {

            claims,

            user: {

              nickname,

              name,

              picture,

              updated_at,

              email,

              email_verified,

              sub,

            },

            audience: '',

            client_id: '',

          },

        },

        expiresAt: exp,

      };


    window.localStorage.setItem('auth0Cypress', JSON.stringify(item));

    return body;

  });

});


let LOCAL_STORAGE_MEMORY = {};

Cypress.Commands.add("saveLocalStorageCache", () => {

  Object.keys(localStorage).forEach(key => {

    LOCAL_STORAGE_MEMORY[key] = localStorage[key];

  });

});


Cypress.Commands.add("restoreLocalStorageCache", () => {

  Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {

    localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);

  });

});


4. With this command added to Cypress.io, I can now login programmatically to Auth0 using the following code in my first test. You'll note that the authenticated user details are being written in local storage (but only during testing), and the Auth0 authenticated token is being stored as a cookie--this is the token that I use with my backend API.


describe('Login', () => {

  beforeEach(() => {

    cy.restoreLocalStorageCache();

  });

  

  it('Should successfully login', () => {

    cy.login2()

      .then((resp) => {

        return resp;

      })

      .then((body) => {

        const {access_token, expires_in, id_token} = body;

        const auth0State = {

          nonce: '',

          state: 'some-random-state'

        };


        // write access token to user-token cookie

        cy.setCookie('user-token', access_token);


        const callbackUrl = `/callback#access_token=${access_token}&scope=openid&id_token=${id_token}&expires_in=${expires_in}&token_type=Bearer&state=${auth0State.state}`;

        cy.visit(callbackUrl, {

          onBeforeLoad(win) {

            win.document.cookie = 'com.auth0.auth.some-random-state=' + JSON.stringify(auth0State);

          }

        });

      })

  });

  afterEach(() => {

    cy.saveLocalStorageCache();

  });

});


6. This all seemed to work great, however, Auth0 still would not recognize that the user is authenticated. The Auth0 client would always return false for isAuthenticated. To get around this issue, I had to hack my AuthGuard.

This is what I had before adding Cypress.io:

return this.auth.isAuthenticated$.pipe(

  tap(loggedIn => {

    if (!loggedIn) {

       this.auth.login(state.url);

    }

 })

);


To get around the issue, I simple added another option. If the code is being run by Cypress, I check for the stored user credential and token. I even added a check that it's the right authenticated user, but that's really not needed.


    // @ts-ignore

    if (window.Cypress) {

      const auth0credentials = JSON.parse(localStorage.getItem("auth0Cypress")!);

      const user = auth0credentials.body.decodedToken.user;

      const access_token = auth0credentials.body.access_token;


      if(user.name === 'youtestuser@yourdomain.com' && access_token) {

        return true;

      } else {

        return this.auth.isAuthenticated$.pipe(

          tap(loggedIn => {

            if (!loggedIn) {

              } else {

                this.auth.login(state.url);

              }

            })

          );

      };

    } else {

      return this.auth.isAuthenticated$.pipe(

        tap(loggedIn => {

          if (!loggedIn) {

            this.auth.login(state.url);

          }

        })

      );

    }


Well, I think that's everything. I hope there is a better answer coming as this hack around the AuthGuard is not a prefect solution, but it does let me move forward and that's promising.