Skip to content
Merged
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
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ <h1>JavaScript Cache API ÖrneK</h1>
<button id="clear-cache">Veriyi Sil</button>
<div id="output"></div>

<script src="script.js"></script>
<script type="module" src="script.ts"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Config } from "@jest/types";

const config: Config.InitialOptions = {
preset: "ts-jest",
testEnvironment: "jsdom",
setupFilesAfterEnv: ["@testing-library/jest-dom"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
transform: {
"^.+\\.tsx?$": "ts-jest",
},
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
coverageThreshold: {
global: {
statements: 70,
branches: 70,
functions: 70,
lines: 70,
},
},
};

export default config;
6,298 changes: 3,173 additions & 3,125 deletions package-lock.json

Large diffs are not rendered by default.

29 changes: 16 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
{
"name": "cache-example",
"version": "1.0.0",
"description": "Cache API örneği",
"main": "script.js",
"description": "",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "jest",
"test:coverage": "jest --coverage"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^6.4.2",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.16",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0"
},
"jest": {
"coverageThreshold": {
"global": {
"statements": 70,
"branches": 70,
"functions": 70,
"lines": 70
}
}
"jest-environment-jsdom": "^29.7.0",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.3.3",
"vite": "^5.0.12"
}
}
64 changes: 45 additions & 19 deletions script.test.js → script.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@
* @jest-environment jsdom
*/

const fs = require("fs");
const path = require("path");
import fs from "fs";
import path from "path";
import "@testing-library/jest-dom";

interface MockCache {
put: jest.Mock;
match: jest.Mock;
}

interface MockCaches {
open: jest.Mock;
delete: jest.Mock;
}

describe("Cache API Tests", () => {
let mockCache;
let mockCache: MockCache;

beforeEach(() => {
// index.html dosyasını yükle
Expand All @@ -22,19 +33,22 @@ describe("Cache API Tests", () => {
match: jest.fn(),
};

global.caches = {
// Global cache tipini tanımla
const globalCaches: MockCaches = {
open: jest.fn().mockResolvedValue(mockCache),
delete: jest.fn().mockResolvedValue(true),
};

global.caches = globalCaches as unknown as CacheStorage;

// navigator.onLine mock
Object.defineProperty(window.navigator, "onLine", {
configurable: true,
value: true,
});

// Fetch API mock
global.fetch = jest.fn().mockImplementation((url) => {
global.fetch = jest.fn().mockImplementation((url: string) => {
if (url === "https://jsonplaceholder.typicode.com") {
return Promise.resolve({ ok: true });
}
Expand All @@ -45,11 +59,11 @@ describe("Cache API Tests", () => {
}),
json: () => Promise.resolve({ id: 1, title: "Test Post" }),
});
});
}) as jest.Mock;

// script.js'i yükle
// script.ts'i yükle
jest.isolateModules(() => {
require("./script.js");
require("./script.ts");
});
});

Expand All @@ -59,8 +73,10 @@ describe("Cache API Tests", () => {
});

test("İnternet bağlantısı varken veri API'den alınmalı", async () => {
const fetchButton = document.getElementById("fetch-data");
const output = document.getElementById("output");
const fetchButton = document.getElementById(
"fetch-data"
) as HTMLButtonElement;
const output = document.getElementById("output") as HTMLDivElement;

await fetchButton.click();

Expand All @@ -73,8 +89,10 @@ describe("Cache API Tests", () => {
});

test("İnternet bağlantısı yokken cache'den veri alınmalı", async () => {
const fetchButton = document.getElementById("fetch-data");
const output = document.getElementById("output");
const fetchButton = document.getElementById(
"fetch-data"
) as HTMLButtonElement;
const output = document.getElementById("output") as HTMLDivElement;

// İnternet bağlantısını kapat
Object.defineProperty(window.navigator, "onLine", {
Expand All @@ -97,8 +115,10 @@ describe("Cache API Tests", () => {
});

test("İnternet ve cache yokken hata mesajı gösterilmeli", async () => {
const fetchButton = document.getElementById("fetch-data");
const output = document.getElementById("output");
const fetchButton = document.getElementById(
"fetch-data"
) as HTMLButtonElement;
const output = document.getElementById("output") as HTMLDivElement;

// İnternet bağlantısını kapat
Object.defineProperty(window.navigator, "onLine", {
Expand All @@ -120,8 +140,10 @@ describe("Cache API Tests", () => {
});

test("Önbellek temizleme işlemi başarılı olmalı", async () => {
const clearButton = document.getElementById("clear-cache");
const output = document.getElementById("output");
const clearButton = document.getElementById(
"clear-cache"
) as HTMLButtonElement;
const output = document.getElementById("output") as HTMLDivElement;

await clearButton.click();

Expand All @@ -130,11 +152,15 @@ describe("Cache API Tests", () => {
});

test("Önbellek temizleme işlemi başarısız olduğunda hata mesajı gösterilmeli", async () => {
const clearButton = document.getElementById("clear-cache");
const output = document.getElementById("output");
const clearButton = document.getElementById(
"clear-cache"
) as HTMLButtonElement;
const output = document.getElementById("output") as HTMLDivElement;

// Silme işleminin başarısız olduğunu simüle et
global.caches.delete.mockRejectedValue(new Error("Silme hatası"));
(global.caches.delete as jest.Mock).mockRejectedValue(
new Error("Silme hatası")
);

await clearButton.click();

Expand Down
50 changes: 28 additions & 22 deletions script.js → script.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
const CACHE_NAME = "my-cache-v1"; // Önbellek ismi
const API_URL = "https://jsonplaceholder.typicode.com/posts/1"; // API URL'i
interface Post {
userId: number;
id: number;
title: string;
body: string;
}

interface DataResponse {
data: Post;
source: "API" | "Cache";
}

const CACHE_NAME = "my-cache-v1";
const API_URL = "https://jsonplaceholder.typicode.com/posts/1";

// DOM elementlerini seç
const fetchButton = document.getElementById("fetch-data");
const clearButton = document.getElementById("clear-cache");
const output = document.getElementById("output");
const fetchButton = document.getElementById("fetch-data") as HTMLButtonElement;
const clearButton = document.getElementById("clear-cache") as HTMLButtonElement;
const output = document.getElementById("output") as HTMLDivElement;

// İnternet bağlantısını kontrol et
async function checkInternetConnection() {
async function checkInternetConnection(): Promise<boolean> {
try {
// navigator.onLine kontrolü
if (!navigator.onLine) {
return false;
}

// Çift kontrol için gerçek bir istek deneyelim
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 saniye timeout
const timeoutId = setTimeout(() => controller.abort(), 5000);

const response = await fetch("https://jsonplaceholder.typicode.com", {
signal: controller.signal,
Expand All @@ -31,25 +41,25 @@ async function checkInternetConnection() {
}

// Veriyi API'den al ve cache'e kaydet
async function fetchAndCacheData() {
async function fetchAndCacheData(): Promise<DataResponse> {
try {
const response = await fetch(API_URL);
const cache = await caches.open(CACHE_NAME);
await cache.put(API_URL, response.clone());
const data = await response.json();
const data = (await response.json()) as Post;
return { data, source: "API" };
} catch (error) {
throw new Error("Veri API'den alınamadı");
}
}

// Cache'den veri getir
async function getCachedData() {
async function getCachedData(): Promise<DataResponse | null> {
try {
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(API_URL);
if (cachedResponse) {
const data = await cachedResponse.json();
const data = (await cachedResponse.json()) as Post;
return { data, source: "Cache" };
}
return null;
Expand All @@ -59,38 +69,34 @@ async function getCachedData() {
}

// Veriyi getir (internet durumuna göre API veya cache'den)
async function getData() {
async function getData(): Promise<void> {
try {
output.textContent = "Veri getiriliyor...";

// Önce cache'i kontrol et
const cachedData = await getCachedData();

// İnternet bağlantısını kontrol et
const isOnline = await checkInternetConnection();

if (isOnline) {
// İnternet varsa API'den al ve cache'e kaydet
const { data } = await fetchAndCacheData();
output.textContent = `Veri API'den alındı ve önbelleğe kaydedildi: ${JSON.stringify(
data
)}`;
console.log("Veri API'den alındı ve önbelleğe kaydedildi");
} else if (cachedData) {
// İnternet yoksa ve cache'de veri varsa
output.textContent = `İnternet bağlantısı yok! Veri önbellekten alındı: ${JSON.stringify(
cachedData.data
)}`;
console.log("Veri önbellekten alındı (offline mod)");
} else {
// Ne internet var ne de cache'de veri var
output.textContent =
"Veri alınamadı! İnternet bağlantısı yok ve önbellekte veri bulunamadı.";
console.log("Veri alınamadı - Bağlantı yok ve önbellek boş");
}
} catch (error) {
output.textContent = `Hata: ${error.message}`;
console.error("Hata:", error);
if (error instanceof Error) {
output.textContent = `Hata: ${error.message}`;
console.error("Hata:", error);
}
}
}

Expand Down
51 changes: 51 additions & 0 deletions searchPerformance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Linear Search
function linearSearch(arr: string[], target: string): number {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i;
}
}
return -1;
}

// Binary Search
function binarySearch(arr: string[], target: string): number {
let left = 0;
let right = arr.length - 1;

while (left <= right) {
const mid = Math.floor((left + right) / 2);

if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}

// Test setup
function testPerformance() {
// Farklı boyutlarda testler yapalım
const sizes = [100, 1000, 10000, 100000, 1000000];

sizes.forEach((size) => {
const arr = Array.from({ length: size }, (_, i) => `item${i}`);
const target = `item${size - 1}`; // En son elemanı arayalım

console.log(`\nDizi boyutu: ${size}`);

console.time("Linear Search");
linearSearch(arr, target);
console.timeEnd("Linear Search");

console.time("Binary Search");
binarySearch(arr, target);
console.timeEnd("Binary Search");
});
}

testPerformance();
Loading
Loading