SamagraX-Stencil / stencil

NestJS on steroids 💪
https://stencil.samagra.io
MIT License
28 stars 28 forks source link

[stencil] tests for file upload interceptor #50

Open techsavvyash opened 6 months ago

techsavvyash commented 6 months ago

Description

There is a file-upload interceptor in the common package which helps enable the file upload functionality in a stencil app by just registering the interceptor wherever required. The task is to add tests for this interceptor.

Goals

Implementational Details

Create a test file named file-upload.interceptor.spec.ts in the tests directory and write the required test cases using jest. Make sure to cover all edge cases.

Product Name

Stencil

Organisation Name

SamagraX

Tech Skills Needed

TypeScript, Jest, SuperTest, Software Testing

Mentors

@techsavvyash

Complexity

Medium

Category

Software Testing

Test Case List

Some of the test cases I would want you to add tests for are:

Saving to local storage

  1. filename is simple: test.txt
  2. file name has multiple periods: text.tar.gz
  3. the service should throw for illegal filenames like: foo/bar.xz or ../foo.txt or foo/../bar.ext
  4. filename without extensions are allowed filename
  5. It is throwing if the STORAGE_ENDPOINT directory does not exist
  6. It is throwing if the destination directory does not exist.
  7. Allowing for files with spaces in the same foo bar.ext
  8. Allows for empty destination parameter and stores in the root of STORAGE_ENDPOINT folder.

Uploading to minIO

Uploads over HTTP (process.env.STORAGE_USE_SSL === false)

  1. The returned urls have http and port number mentioned
  2. All the cases from # Saving to local storage while treating STORAGE_ENDPOINT as the minio endpoint and destination as the bucket name.

Uploads pver HTTPS (process.env.STORAGE_USE_SSL === true)

  1. Returned urls have https always but only contain port numbers in case of direct IPv4 or IPv6 addresses in the STORAGE_ENDPOINT. (For example returned url should look like: https://<IP>:<PORT>/destination/filename)
  2. Returned urls have https but not the port number in case the STORAGE_ENDPOINT is a proper url such as cdn-api.dev.samagra.io. (For example returned url should look like: https://cdn-api.dev.samagra.io/destination/filename)
  3. All the cases from # Saving to local storage while treating STORAGE_ENDPOINT as the minio endpoint and destination as the bucket name.

Make-Bucket Endpoint

  1. Test the make-bucket endpoint for local storage
  2. Test the make-bucket endpoint for minio

Downloads

  1. make sure illegal destination parameters like ../foo/bar are rejected right of the back.
  2. Make sure test case 1 for filenames as well.
  3. Make sure we are able to retrieve the file we uploaded correctly when passing legal params.

Ad-Hoc

c4gt-community-support[bot] commented 5 months ago

Hi! Important Details - These following details are helpful for contributors to effectively identify and contribute to tickets.

Please update the ticket

Gmin2 commented 5 months ago

Hey @techsavvyash i am familiar with jest can i work on this?

techsavvyash commented 5 months ago

Please go ahead @Min2who assigning this to you

vsvishalsharma commented 4 months ago

Hi @techsavvyash sir as I was working on integrating bun.js ,I came across this issue and I think it is solvable shall i try

techsavvyash commented 4 months ago

Hey @vsvishalsharma, This is being already worked upon, I suggest you focus on the Bun.js ticket itself.

vsvishalsharma commented 4 months ago

@techsavvyash sure sir

Yash-Sajwan24 commented 4 months ago

@techsavvyash I understand the problem, and I believe I have the necessary skills. Could I have the opportunity to work on this?

vsvishalsharma commented 4 months ago

@techsavvyash this is the initial code i have implemented:

`import { ExecutionContext } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { Observable,of } from 'rxjs';
import { FastifyFileInterceptor } from '../src/interceptors/file-upload.interceptor';

describe('FastifyFileInterceptor', () => {
  let interceptor: FastifyFileInterceptor;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [FastifyFileInterceptor],
    }).compile();

    interceptor = module.get<FastifyFileInterceptor>(FastifyFileInterceptor);
  });

  it('should be defined', () => {
    expect(interceptor).toBeDefined();
  });

  it('should handle file upload', async () => {
    const context: ExecutionContext = {
      switchToHttp: jest.fn(() => ({
        getRequest: jest.fn(() => ({
          file: {}, 
        })),
        getResponse: jest.fn(),
      })),
      switchToRpc: jest.fn(),
      switchToWs: jest.fn(),
    };

    const nextHandler = {
      handle: jest.fn(() => of('')),
    };

    await interceptor.intercept(context, nextHandler);

    expect(context.switchToHttp().getRequest).toHaveBeenCalled();
    expect(context.switchToHttp().getResponse).toHaveBeenCalled();

    expect(nextHandler.handle).toHaveBeenCalled();
  });

  it('should handle getting an uploaded file', async () => {
    const file = { /* mock file object */ };
    const context: ExecutionContext = {
      switchToHttp: jest.fn(() => ({
        getRequest: jest.fn(() => ({
          file: file, 
        })),
        getResponse: jest.fn(),
      })),
      switchToRpc: jest.fn(),
      switchToWs: jest.fn(),
    };

    const nextHandler = {
      handle: jest.fn(() => of('')),
    };

    await interceptor.intercept(context, nextHandler);

    expect(context.switchToHttp().getRequest).toHaveBeenCalled();
    expect(context.switchToHttp().getResponse).toHaveBeenCalled();

    // Assert that the uploaded file is passed to the next handler
    expect(nextHandler.handle).toHaveBeenCalledWith(file);
  });

  it('should handle errors', async () => {
    const context: ExecutionContext = {
      switchToHttp: jest.fn(() => ({
        getRequest: jest.fn(() => ({
          file: {}, 
        })),
        getResponse: jest.fn(),
      })),
      switchToRpc: jest.fn(),
      switchToWs: jest.fn(),
    };

    const errorMessage = 'File upload failed';
    const nextHandler = {
      handle: jest.fn(() => throwError(errorMessage)),
    };

    try {
      await interceptor.intercept(context, nextHandler);
    } catch (error) {
      expect(error.message).toBe(errorMessage);
    }

    expect(context.switchToHttp().getRequest).toHaveBeenCalled();
    expect(context.switchToHttp().getResponse).toHaveBeenCalled();
    expect(nextHandler.handle).toHaveBeenCalled();
  });
});
 `
techsavvyash commented 4 months ago

@vsvishalsharma please go ahead and raise a draft PR

deecodess commented 2 months ago

Hey @techsavvyash I also tried my hands on it and I guess I have pretty much done the required task Can you please assign this to me and can I raise the PR fo it ?

techsavvyash commented 2 months ago

hey @deecodess if you have tests ready, please raise a PR. This is a long running test case and we only assign issues once a draft PR has been raised.