diff --git a/README.md b/README.md index 11d4a76..a7ef8b5 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,21 @@ reset: () => void; perform: (steps: string | string[]) => Promise; ``` +### Additional Note + +In addition to the operations history, Copilot maintains a repository-level cache. If you need to ignore the current cache for any reason (e.g., when adding an action to the testing framework driver), you can set the environment variable `COPILOT_OVERRIDE_CACHE` to "true" before running your tests. This will ensure that the current cache is not taken into consideration and will override the existing one. + +```shell +export COPILOT_OVERRIDE_CACHE=true +``` + +If you want to disable the override after setting it to "true" and revert to using the cache, you can set `COPILOT_OVERRIDE_CACHE` to "false" + +```shell +export COPILOT_OVERRIDE_CACHE=false +``` + + ## Integration with Testing Frameworks Detox Copilot requires two main components to work: diff --git a/src/actions/StepPerformer.test.ts b/src/actions/StepPerformer.test.ts index af0fbc2..179f2a1 100644 --- a/src/actions/StepPerformer.test.ts +++ b/src/actions/StepPerformer.test.ts @@ -73,6 +73,7 @@ describe('StepPerformer', () => { promptResult?: string; codeEvaluationResult?: any; cacheExists?: boolean; + overrideCache?: boolean; } const setupMocks = ({ @@ -82,6 +83,7 @@ describe('StepPerformer', () => { promptResult = 'generated code', codeEvaluationResult = 'success', cacheExists = false, + overrideCache = false, }: SetupMockOptions = {}) => { mockPromptHandler.isSnapshotImageSupported.mockReturnValue(isSnapshotSupported); mockSnapshotManager.captureSnapshotImage.mockResolvedValue( @@ -92,6 +94,10 @@ describe('StepPerformer', () => { mockPromptHandler.runPrompt.mockResolvedValue(promptResult); mockCodeEvaluator.evaluate.mockResolvedValue(codeEvaluationResult); + if (overrideCache) { + process.env.COPILOT_OVERRIDE_CACHE = "true"; + } + const viewHierarchyHash = 'hash'; (crypto.createHash as jest.Mock).mockReturnValue({ update: jest.fn().mockReturnValue({ @@ -244,4 +250,18 @@ describe('StepPerformer', () => { expect(mockCodeEvaluator.evaluate).not.toHaveBeenCalled(); expect(fs.writeFileSync).not.toHaveBeenCalled(); }); + + it('should not use cached prompt result if COPILOT_OVERRIDE_CACHE is enabled', async () => { + const intent = 'tap button'; + setupMocks({ cacheExists: true, overrideCache: true }); + + const result = await stepPerformer.perform(intent); + + expect(result).toBe('success'); + // Should call runPrompt or createPrompt. Shouldn't use current cache, but override it + expect(mockPromptCreator.createPrompt).toHaveBeenCalled(); + expect(mockPromptHandler.runPrompt).toHaveBeenCalled(); + expect(mockCodeEvaluator.evaluate).toHaveBeenCalledWith('generated code', mockContext); + expect(fs.writeFileSync).toHaveBeenCalled(); // Need to save cache + }); }); diff --git a/src/actions/StepPerformer.ts b/src/actions/StepPerformer.ts index 066db6a..3a430bf 100644 --- a/src/actions/StepPerformer.ts +++ b/src/actions/StepPerformer.ts @@ -62,6 +62,10 @@ export class StepPerformer { return { snapshot, viewHierarchy, isSnapshotImageAttached }; } + private shouldOverrideCache() { + return process.env.COPILOT_OVERRIDE_CACHE === "true" || process.env.COPILOT_OVERRIDE_CACHE === "1"; + } + private async generateCode( step: string, previous: PreviousStep[], @@ -71,7 +75,7 @@ export class StepPerformer { ): Promise { const cacheKey = this.generateCacheKey(step, previous, viewHierarchy); - if (this.cache.has(cacheKey)) { + if (!this.shouldOverrideCache() && this.cache.has(cacheKey)) { return this.cache.get(cacheKey); } else { const prompt = this.promptCreator.createPrompt(step, viewHierarchy, isSnapshotImageAttached, previous);