Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,14 @@
},
"devDependencies": {
"vitest": "^4.0.18"
}
},
"main": "vitest.config.js",
"repository": {
"type": "git",
"url": "git+https://github.com/Unlock7/c55-core-week-10.git"
},
"bugs": {
"url": "https://github.com/Unlock7/c55-core-week-10/issues"
},
"homepage": "https://github.com/Unlock7/c55-core-week-10#readme"
}
54 changes: 51 additions & 3 deletions task-1/cocktail.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// API documentation: https://www.thecocktaildb.com/api.php

import path from 'path';
import path from "path";
import fs from "fs/promises";

const BASE_URL = 'https://www.thecocktaildb.com/api/json/v1/1';
const BASE_URL = "https://www.thecocktaildb.com/api/json/v1/1";

// Add helper functions as needed here

export async function main() {
if (process.argv.length < 3) {
console.error('Please provide a cocktail name as a command line argument.');
console.error("Please provide a cocktail name as a command line argument.");
return;
}

Expand All @@ -22,7 +23,54 @@ export async function main() {
// 1. Fetch data from the API at the given URL
// 2. Generate markdown content to match the examples
// 3. Write the generated content to a markdown file as given by outPath

const res = await fetch(url);
const data = await res.json();

if (!res.ok) {
const error = new Error(data.error || res.statusText);

error.status = res.status;

throw error;
}

if (!data.drinks) {
console.error("No cocktails found with that name.");
return;
}

let markdown = "# Cocktail Recipes\n\n";

for (const drink of data.drinks) {
markdown += `## ${drink.strDrink}\n\n`;
markdown += `![${drink.strDrink}](${drink.strDrinkThumb}/medium)\n\n`;
markdown += `**Category**: ${drink.strCategory}\n`;

const isAlcoholic = drink.strAlcoholic === "Alcoholic" ? "Yes" : "No";
markdown += `**Alcoholic**: ${isAlcoholic}\n\n`;

markdown += `### Ingredients\n\n`;
for (let i = 1; i <= 15; i++) {
const ingredient = drink[`strIngredient${i}`];
const measure = drink[`strMeasure${i}`];
if (ingredient) {
const amount = measure ? `${measure.trim()} ` : "";
markdown += `- ${amount}${ingredient.trim()}\n`;
}
}

markdown += `\n### Instructions\n\n`;
markdown += `${drink.strInstructions}\n\n`;
markdown += `Serve in: ${drink.strGlass}\n\n`;
}

const outputDir = path.dirname(outPath);
await fs.mkdir(outputDir, { recursive: true });
await fs.writeFile(outPath, markdown.trim() + "\n");
} catch (error) {
console.error("Error occured:", error.message);

// 4. Handle errors
}
}
Expand Down
1 change: 0 additions & 1 deletion task-1/examples/margarita.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,3 @@ Serve in: Cocktail glass
In a mason jar muddle the watermelon and 5 mint leaves together into a puree and strain. Next add the grapefruit juice, juice of half a lime and the tequila as well as some ice. Put a lid on the jar and shake. Pour into a glass and add more ice. Garnish with fresh mint and a small slice of watermelon.

Serve in: Collins glass

21 changes: 21 additions & 0 deletions task-1/output/margarita.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Cocktail Recipes

## Margarita

![Margarita](https://www.thecocktaildb.com/images/media/drink/5noda61589575158.jpg/medium)

**Category**: Ordinary Drink
**Alcoholic**: Yes

### Ingredients

- 1 1/2 oz Tequila
- 1/2 oz Triple sec
- 1 oz Lime juice
- Salt

### Instructions

Rub the rim of the glass.

Serve in: Cocktail glass
94 changes: 47 additions & 47 deletions task-1/tests/cocktail.test.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import fs from 'fs/promises';
import path from 'path';
import { beforeAll, describe, expect, test, vi } from 'vitest';
import fs from "fs/promises";
import path from "path";
import { beforeAll, describe, expect, test, vi } from "vitest";

import { main } from '../cocktail.js';
import { main } from "../cocktail.js";

import { data } from './drinks.js';
import { data } from "./drinks.js";

let lines = [];

beforeAll(async () => {
const originalArgv = process.argv;
process.argv = ['node', 'main.js', 'margarita']; // Example cocktail name
process.argv = ["node", "main.js", "margarita"]; // Example cocktail name

global.fetch = vi.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(data),
})
}),
);

// Mock console.log to suppress output during test
Expand All @@ -34,69 +34,69 @@ beforeAll(async () => {
console.log = originalConsoleLog;

try {
const content = await fs.readFile(outPath, 'utf-8');
lines = content.trim().split('\n');
const content = await fs.readFile(outPath, "utf-8");
lines = content.trim().split("\n");
} catch (error) {
console.error('Error reading generated markdown file:', error);
console.error("Error reading generated markdown file:", error);
}
});

describe('Content tests', () => {
test('[10] Markdown file created', async () => {
describe("Content tests", () => {
test("[10] Markdown file created", async () => {
expect(lines.length).toBeGreaterThan(0);
});

test('[1] Content starts with # Cocktail Recipes', async () => {
expect(lines[0]).toBe('# Cocktail Recipes');
test("[1] Content starts with # Cocktail Recipes", async () => {
expect(lines[0]).toBe("# Cocktail Recipes");
});

test('[1] Content includes drink name as ## Margarita', async () => {
expect(lines).toContain('## Margarita');
test("[1] Content includes drink name as ## Margarita", async () => {
expect(lines).toContain("## Margarita");
});

test('[1] Content includes medium drink image', async () => {
test("[1] Content includes medium drink image", async () => {
expect(lines).toContain(
'![Margarita](https://www.thecocktaildb.com/images/media/drink/5noda61589575158.jpg/medium)'
"![Margarita](https://www.thecocktaildb.com/images/media/drink/5noda61589575158.jpg/medium)",
);
});

test('[1] Content includes category and alcoholic info', async () => {
expect(lines).toContain('**Category**: Ordinary Drink');
expect(lines).toContain('**Alcoholic**: Yes');
test("[1] Content includes category and alcoholic info", async () => {
expect(lines).toContain("**Category**: Ordinary Drink");
expect(lines).toContain("**Alcoholic**: Yes");
});

test('[1] Content includes header ### Ingredients', async () => {
expect(lines).toContain('### Ingredients');
test("[1] Content includes header ### Ingredients", async () => {
expect(lines).toContain("### Ingredients");
});

test('[1] Content includes ingredients list', async () => {
expect(lines).toContain('- 1 1/2 oz Tequila');
expect(lines).toContain('- 1/2 oz Triple sec');
expect(lines).toContain('- 1 oz Lime juice');
expect(lines).toContain('- Salt');
test("[1] Content includes ingredients list", async () => {
expect(lines).toContain("- 1 1/2 oz Tequila");
expect(lines).toContain("- 1/2 oz Triple sec");
expect(lines).toContain("- 1 oz Lime juice");
expect(lines).toContain("- Salt");
});

test('[1] Content includes header ### Instructions', async () => {
expect(lines).toContain('### Instructions');
test("[1] Content includes header ### Instructions", async () => {
expect(lines).toContain("### Instructions");
});

test('[1] Content includes instruction details', async () => {
expect(lines).toContain('Rub the rim of the glass.');
test("[1] Content includes instruction details", async () => {
expect(lines).toContain("Rub the rim of the glass.");
});

test('[1] Content includes glass type', async () => {
expect(lines).toContain('Serve in: Cocktail glass');
test("[1] Content includes glass type", async () => {
expect(lines).toContain("Serve in: Cocktail glass");
});
});

describe('Error handling', () => {
test('[1] Calls console.error() if no cocktail name argument provided', async () => {
describe("Error handling", () => {
test("[1] Calls console.error() if no cocktail name argument provided", async () => {
const originalArgv = process.argv;
process.argv = ['node', 'main.js']; // No cocktail name
process.argv = ["node", "main.js"]; // No cocktail name

// Mock console.log to capture output
const consoleErrorMock = vi
.spyOn(console, 'error')
.spyOn(console, "error")
.mockImplementation(() => {});

await main();
Expand All @@ -108,26 +108,26 @@ describe('Error handling', () => {
consoleErrorMock.mockRestore();
});

test('[1] Calls console.error() if cocktail not found', async () => {
test("[1] Calls console.error() if cocktail not found", async () => {
const originalArgv = process.argv;
process.argv = ['node', 'main.js', 'nonexistentcocktail']; // Example cocktail name
process.argv = ["node", "main.js", "nonexistentcocktail"]; // Example cocktail name

global.fetch = vi.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ drinks: null }),
})
}),
);

// Mock console.log to capture output
const consoleLogMock = vi
.spyOn(console, 'error')
.spyOn(console, "error")
.mockImplementation(() => {});

await main();

expect(consoleLogMock).toHaveBeenCalledWith(
expect.stringContaining('No cocktails found with that name.')
expect.stringContaining("No cocktails found with that name."),
);

// Restore original process.argv and console.log
Expand All @@ -137,21 +137,21 @@ describe('Error handling', () => {
expect(fetch).toHaveBeenCalledTimes(1);
});

test('[1] Calls console.error() if fetch was not OK', async () => {
test("[1] Calls console.error() if fetch was not OK", async () => {
const originalArgv = process.argv;
process.argv = ['node', 'main.js', 'margarita']; // Example cocktail name
process.argv = ["node", "main.js", "margarita"]; // Example cocktail name

global.fetch = vi.fn(() =>
Promise.resolve({
ok: false,
status: 500,
json: () => Promise.resolve({}),
})
}),
);

// Mock console.log to suppress output during test
const consoleErrorMock = vi
.spyOn(console, 'error')
.spyOn(console, "error")
.mockImplementation(() => {});

await main();
Expand Down
Loading