Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Journeys not being bundled correctly when using modules in journey/ subdirectory #905

Open
renzedj opened this issue Mar 27, 2024 · 2 comments
Labels
question Further information is requested

Comments

@renzedj
Copy link

renzedj commented Mar 27, 2024

I initially thought that this was the same issue as Issue #693, but I did a deeper dive after the response I got on that issue and think that while it may be related, it's not the same issue.

I am using a factory pattern to generate identical tests which run against multiple endpoints. When I separate the factory module from the journey file, only the factory module is bundled by NPM and pushed to the cluster.

This has been validated with @elastic/synthetics-1.7.2.

Steps to reproduce

  1. Initialize a new @elastic/synthetics project.
  2. Create the following files:
/**
 * File 1: journeys/journey-factory.journey.ts
 */
import { JourneyFactory } from './modules/journey-factory';

const googleJourney = new JourneyFactory().createJourney();
googleJourney();
/**
 * File 2: journeys/modules/journey-factory.ts
 */
import { journey, step, monitor, expect } from '@elastic/synthetics';

interface JourneyFunction {
  (): Promise<void>;
}

export class JourneyFactory {
  private env: string;  // Test environment

  createJourney(): JourneyFunction {
    return this.syntheticsJourney;
  }

  // Journey function
  syntheticsJourney = async (): Promise<void> => {
    journey(`google_factory_test`, ({ page, params }) => {
      monitor.use({
        id: '35a0908a-dac1-4c95-ba9c-28afbe1b4c07',
        schedule: 5,
        tags: ['google', 'factory', 'module', 'test',],
      });

      step('Open URL', async () => {
        await page.goto('https://www.google.com/');
        await expect(page.getByText('Google')).toBeTruthy();
      });
    });
  }
}
  1. Run locally: npx @elastic/synthetics .
  2. Push to remote.

Results

Everything runs as expected when running locally from the command line with npx @elastic/synthetics ..

When I push it to my Elastic Cluster, it generates the following error:

image

When I look at the correct folder on the Agent, I see the following:

root@elastic-synthetics-agent-XXXXXXXXXX-XXXXX:/tmp/elastic-synthetics-unzip-XXXXXXXXXX/journeys# ls -l
total 0
drwxrwx--- 2 root root 32 Mar 19 14:04 modules
root@elastic-synthetics-agent-XXXXXXXXXX-XXXXX:/tmp/elastic-synthetics-unzip-XXXXXXXXXX/journeys# ls -l modules/
total 4
-rwxrwx--- 1 root root 2039 Mar 19 14:04 journey-factory.ts
root@elastic-synthetics-agent-XXXXXXXXXX-XXXXX:/tmp/elastic-synthetics-unzip-XXXXXXXXXX/journeys/modules#

When I examine the contents of journey-factory.ts, it corresponds to the module, I'm not able to find the actual journey file.

If I define the factory class and instantiate it in the same file, everything runs as expected.

Originally posted by @renzedj in #693 (comment)

@vigneshshanmugam vigneshshanmugam added the question Further information is requested label Mar 28, 2024
@vigneshshanmugam
Copy link
Member

Thanks for raising the issue @renzedj, The way push command works is by

  • Traversing for all the journey invocations and then getting the location information of these files
  • Bundling them and pushing them over to the Kibana backend

Since the factory contains the invocation of the journey() inside the Class definition itself, the journey-factory.journey.ts is not useful here since its not doing anything other than calling the invoker itself where the actual journey is defined. The other issue is, even though the bundle contains the all the necessary information to run the required journey, The reason why its failing is because the filename is journey-factory.ts, Synthetics runner by default looks for files that are matching /*.journey.(ts|js)$/ format. Since the filename is not matched, the run yields no Steps to run.

We follow similar factory patterns, but try to do one of these things

  1. Either move the helper function inside helper.journey.ts and let the caller invoke different journeys based on individual configuration (be it journey name, environments, etc).
  2. Keep the journey invocation in the corresponding file and use a helper API for the individual steps.
import {createJourney} from "./helper";
import {journey} from "@elastic/synthetics";

journey("name", async() => {
   createJourney();
})

Let us know if you have more questions or feedback. Thanks.

@renzedj
Copy link
Author

renzedj commented Mar 29, 2024

Thanks for raising the issue @renzedj, The way push command works is by

  • Traversing for all the journey invocations and then getting the location information of these files
  • Bundling them and pushing them over to the Kibana backend

This is what I suspected, when I compared it with the way that the advanced-example.journey.ts handles the import. Can you please clarify this in the documentation? Knowing this, I get this from documentation. But without knowing it in advance, it reads like it starts from *.journey.ts and traverses from there.

Since the factory contains the invocation of the journey() inside the Class definition itself, the journey-factory.journey.ts is not useful here since its not doing anything other than calling the invoker itself where the actual journey is defined. The other issue is, even though the bundle contains the all the necessary information to run the required journey, The reason why its failing is because the filename is journey-factory.ts, Synthetics runner by default looks for files that are matching /*.journey.(ts|js)$/ format. Since the filename is not matched, the run yields no Steps to run.

While I can see why the decision was made to go with this for bundling, IMO this limits the utility of the factory pattern, which would otherwise be able to return a complete journey to be invoked, like in the example I provided. If the synthetics agent looks for the *.journey.(js|ts) to execute, then the bundling SHOULD do the same. Seems to me that this would also make it easier to scan for journeys, as you don't have to open each file to look for the journey definition. Doing this would also allow the use of feature flags to more easily promote tests through regions.

While I realize that this would likely be lower in priority, I would like to request this as a change. This SHOULD NOT be a breaking change, as anything written assuming the current bundling method would still work, since it's defining the journey in the journey file.

We follow similar factory patterns, but try to do one of these things

  1. Either move the helper function inside helper.journey.ts and let the caller invoke different journeys based on individual configuration (be it journey name, environments, etc).
  2. Keep the journey invocation in the corresponding file and use a helper API for the individual steps.
import {createJourney} from "./helper";
import {journey} from "@elastic/synthetics";

journey("name", async() => {
   createJourney();
})

Let us know if you have more questions or feedback. Thanks.

The first is what I'm doing now and it's less than optimum. The second is the next thing I was going to try on this. Thanks for the confirmation. Thx also for the quick response, even if it's not what I wanted to hear. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants